mirror of
https://github.com/izzy2lost/xenia-edge.git
synced 2026-07-06 00:20:26 -07:00
[UI] Fix post-processing dialog.
Should now have correct sharpening options and work right with gamepad input. Also fixing the per-game UI override as that had an extra entry for some reason.
This commit is contained in:
@@ -1005,6 +1005,13 @@ void EmulatorWindow::UpdateDitherCvar(bool value) {
|
||||
}
|
||||
}
|
||||
|
||||
void EmulatorWindow::UpdateFsrMaxUpsamplingPassesCvar(uint32_t value) {
|
||||
auto cvars_config = GetGuestOutputPaintConfigForCvars();
|
||||
if (cvars_config.GetFsrMaxUpsamplingPasses() != value) {
|
||||
OVERRIDE_uint32(postprocess_ffx_fsr_max_upsampling_passes, value);
|
||||
}
|
||||
}
|
||||
|
||||
void EmulatorWindow::OnKeyDown(ui::KeyEvent& e) {
|
||||
if (!emulator_initialized_) {
|
||||
return;
|
||||
|
||||
@@ -131,6 +131,7 @@ class EmulatorWindow {
|
||||
void UpdateScalingAndSharpeningCvar(
|
||||
ui::Presenter::GuestOutputPaintConfig::Effect effect);
|
||||
void UpdateFsrSharpnessCvar(float value);
|
||||
void UpdateFsrMaxUpsamplingPassesCvar(uint32_t value);
|
||||
void UpdateCasSharpnessCvar(float value);
|
||||
void UpdateDitherCvar(bool value);
|
||||
|
||||
@@ -170,6 +171,22 @@ class EmulatorWindow {
|
||||
}
|
||||
};
|
||||
|
||||
// For comparisons, use GetSwapPostEffectForCvarValue instead as the default
|
||||
// fallback may be used for multiple values.
|
||||
static const char* GetCvarValueForSwapPostEffect(
|
||||
gpu::CommandProcessor::SwapPostEffect effect);
|
||||
static gpu::CommandProcessor::SwapPostEffect GetSwapPostEffectForCvarValue(
|
||||
const std::string& cvar_value);
|
||||
// For comparisons, use GetGuestOutputPaintEffectForCvarValue instead as the
|
||||
// default fallback may be used for multiple values.
|
||||
static const char* GetCvarValueForGuestOutputPaintEffect(
|
||||
ui::Presenter::GuestOutputPaintConfig::Effect effect);
|
||||
static ui::Presenter::GuestOutputPaintConfig::Effect
|
||||
GetGuestOutputPaintEffectForCvarValue(const std::string& cvar_value);
|
||||
static ui::Presenter::GuestOutputPaintConfig
|
||||
GetGuestOutputPaintConfigForCvars();
|
||||
void ApplyDisplayConfigForCvars();
|
||||
|
||||
private:
|
||||
class EmulatorWindowListener final : public ui::WindowListener,
|
||||
public ui::WindowInputListener {
|
||||
@@ -198,22 +215,6 @@ class EmulatorWindow {
|
||||
|
||||
bool Initialize();
|
||||
|
||||
// For comparisons, use GetSwapPostEffectForCvarValue instead as the default
|
||||
// fallback may be used for multiple values.
|
||||
static const char* GetCvarValueForSwapPostEffect(
|
||||
gpu::CommandProcessor::SwapPostEffect effect);
|
||||
static gpu::CommandProcessor::SwapPostEffect GetSwapPostEffectForCvarValue(
|
||||
const std::string& cvar_value);
|
||||
// For comparisons, use GetGuestOutputPaintEffectForCvarValue instead as the
|
||||
// default fallback may be used for multiple values.
|
||||
static const char* GetCvarValueForGuestOutputPaintEffect(
|
||||
ui::Presenter::GuestOutputPaintConfig::Effect effect);
|
||||
static ui::Presenter::GuestOutputPaintConfig::Effect
|
||||
GetGuestOutputPaintEffectForCvarValue(const std::string& cvar_value);
|
||||
static ui::Presenter::GuestOutputPaintConfig
|
||||
GetGuestOutputPaintConfigForCvars();
|
||||
void ApplyDisplayConfigForCvars();
|
||||
|
||||
void OnKeyDown(ui::KeyEvent& e);
|
||||
void OnMouseDown(const ui::MouseEvent& e);
|
||||
void OnMouseDoubleClick(const ui::MouseEvent& e);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "xenia/base/string.h"
|
||||
#include "xenia/base/string_buffer.h"
|
||||
#include "xenia/base/system.h"
|
||||
#include "xenia/emulator.h"
|
||||
#include "xenia/ui/config_helpers.h"
|
||||
|
||||
toml::parse_result ParseFile(const std::filesystem::path& filename) {
|
||||
@@ -271,6 +272,90 @@ void SaveGameConfig(uint32_t title_id, const toml::table& config_table) {
|
||||
}
|
||||
}
|
||||
|
||||
void SaveGameConfigSetting(xe::Emulator* emulator, const char* section,
|
||||
const char* cvar_name, const std::string& value) {
|
||||
if (!emulator || !emulator->is_title_open()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t title_id = emulator->title_id();
|
||||
toml::table config_table = LoadGameConfig(title_id);
|
||||
|
||||
if (!config_table.contains(section)) {
|
||||
config_table.insert(section, toml::table{});
|
||||
}
|
||||
|
||||
auto* section_table = config_table[section].as_table();
|
||||
if (section_table) {
|
||||
section_table->insert_or_assign(cvar_name, value);
|
||||
}
|
||||
|
||||
SaveGameConfig(title_id, config_table);
|
||||
}
|
||||
|
||||
void SaveGameConfigSetting(xe::Emulator* emulator, const char* section,
|
||||
const char* cvar_name, bool value) {
|
||||
if (!emulator || !emulator->is_title_open()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t title_id = emulator->title_id();
|
||||
toml::table config_table = LoadGameConfig(title_id);
|
||||
|
||||
if (!config_table.contains(section)) {
|
||||
config_table.insert(section, toml::table{});
|
||||
}
|
||||
|
||||
auto* section_table = config_table[section].as_table();
|
||||
if (section_table) {
|
||||
section_table->insert_or_assign(cvar_name, value);
|
||||
}
|
||||
|
||||
SaveGameConfig(title_id, config_table);
|
||||
}
|
||||
|
||||
void SaveGameConfigSetting(xe::Emulator* emulator, const char* section,
|
||||
const char* cvar_name, uint32_t value) {
|
||||
if (!emulator || !emulator->is_title_open()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t title_id = emulator->title_id();
|
||||
toml::table config_table = LoadGameConfig(title_id);
|
||||
|
||||
if (!config_table.contains(section)) {
|
||||
config_table.insert(section, toml::table{});
|
||||
}
|
||||
|
||||
auto* section_table = config_table[section].as_table();
|
||||
if (section_table) {
|
||||
section_table->insert_or_assign(cvar_name, value);
|
||||
}
|
||||
|
||||
SaveGameConfig(title_id, config_table);
|
||||
}
|
||||
|
||||
void SaveGameConfigSetting(xe::Emulator* emulator, const char* section,
|
||||
const char* cvar_name, double value) {
|
||||
if (!emulator || !emulator->is_title_open()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t title_id = emulator->title_id();
|
||||
toml::table config_table = LoadGameConfig(title_id);
|
||||
|
||||
if (!config_table.contains(section)) {
|
||||
config_table.insert(section, toml::table{});
|
||||
}
|
||||
|
||||
auto* section_table = config_table[section].as_table();
|
||||
if (section_table) {
|
||||
section_table->insert_or_assign(cvar_name, value);
|
||||
}
|
||||
|
||||
SaveGameConfig(title_id, config_table);
|
||||
}
|
||||
|
||||
toml::table LoadGameConfig(uint32_t title_id) {
|
||||
const auto game_config_path =
|
||||
config_folder / "config" /
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
#include <functional>
|
||||
#include "third_party/tomlplusplus/toml.hpp"
|
||||
|
||||
namespace xe {
|
||||
class Emulator;
|
||||
} // namespace xe
|
||||
|
||||
toml::parse_result ParseFile(const std::filesystem::path& filename);
|
||||
|
||||
namespace config {
|
||||
@@ -25,6 +29,14 @@ std::vector<std::string> LoadGameConfigAsArgs(const std::string_view title_id);
|
||||
toml::table LoadGameConfig(uint32_t title_id);
|
||||
void SaveConfig();
|
||||
void SaveGameConfig(uint32_t title_id, const toml::table& config_table);
|
||||
void SaveGameConfigSetting(xe::Emulator* emulator, const char* section,
|
||||
const char* cvar_name, const std::string& value);
|
||||
void SaveGameConfigSetting(xe::Emulator* emulator, const char* section,
|
||||
const char* cvar_name, bool value);
|
||||
void SaveGameConfigSetting(xe::Emulator* emulator, const char* section,
|
||||
const char* cvar_name, uint32_t value);
|
||||
void SaveGameConfigSetting(xe::Emulator* emulator, const char* section,
|
||||
const char* cvar_name, double value);
|
||||
void ReloadConfig();
|
||||
void SetConfigSavedCallback(std::function<void()> callback);
|
||||
} // namespace config
|
||||
|
||||
@@ -82,8 +82,7 @@ GetKnownEnumOptions() {
|
||||
{"readback_resolve", {"fast", "some", "full", "none"}},
|
||||
{"render_target_path", {"performance", "accuracy"}},
|
||||
{"postprocess_antialiasing", {"off", "fxaa", "fxaa_extreme"}},
|
||||
{"postprocess_scaling_and_sharpening",
|
||||
{"bilinear", "cas", "fsr", "nearest"}},
|
||||
{"postprocess_scaling_and_sharpening", {"none", "cas", "fsr"}},
|
||||
{"spirv_version_override", {"auto", "1.0", "1.3", "1.4", "1.5", "1.6"}},
|
||||
{"xma_decoder", {"old", "new", "master", "fake"}},
|
||||
{"user_language",
|
||||
|
||||
@@ -48,6 +48,8 @@ class GamepadDialog : public QDialog {
|
||||
// Override to customize which widgets are focusable
|
||||
virtual bool IsWidgetGamepadFocusable(QWidget* widget) const;
|
||||
|
||||
void UpdateFocusableWidgets();
|
||||
|
||||
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||
void showEvent(QShowEvent* event) override;
|
||||
|
||||
@@ -55,7 +57,6 @@ class GamepadDialog : public QDialog {
|
||||
void PollGamepad();
|
||||
|
||||
private:
|
||||
void UpdateFocusableWidgets();
|
||||
void NavigateFocusVertical(int direction);
|
||||
void NavigateFocusHorizontal(int direction);
|
||||
void AcceptFocusedButton();
|
||||
|
||||
@@ -322,58 +322,6 @@ void PerformanceTuningDialogQt::LoadCurrentSettings() {
|
||||
clear_memory_checkbox_->blockSignals(false);
|
||||
}
|
||||
|
||||
void PerformanceTuningDialogQt::SaveToGameConfig(const char* cvar_name,
|
||||
const std::string& value) {
|
||||
auto emulator = emulator_window_->emulator();
|
||||
if (!emulator || !emulator->is_title_open()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t title_id = emulator->title_id();
|
||||
if (title_id == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
toml::table config_table = config::LoadGameConfig(title_id);
|
||||
|
||||
if (!config_table.contains("GPU")) {
|
||||
config_table.insert("GPU", toml::table{});
|
||||
}
|
||||
|
||||
auto* gpu_table = config_table["GPU"].as_table();
|
||||
if (gpu_table) {
|
||||
gpu_table->insert_or_assign(cvar_name, value);
|
||||
}
|
||||
|
||||
config::SaveGameConfig(title_id, config_table);
|
||||
}
|
||||
|
||||
void PerformanceTuningDialogQt::SaveToGameConfig(const char* cvar_name,
|
||||
bool value) {
|
||||
auto emulator = emulator_window_->emulator();
|
||||
if (!emulator || !emulator->is_title_open()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t title_id = emulator->title_id();
|
||||
if (title_id == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
toml::table config_table = config::LoadGameConfig(title_id);
|
||||
|
||||
if (!config_table.contains("GPU")) {
|
||||
config_table.insert("GPU", toml::table{});
|
||||
}
|
||||
|
||||
auto* gpu_table = config_table["GPU"].as_table();
|
||||
if (gpu_table) {
|
||||
gpu_table->insert_or_assign(cvar_name, value);
|
||||
}
|
||||
|
||||
config::SaveGameConfig(title_id, config_table);
|
||||
}
|
||||
|
||||
void PerformanceTuningDialogQt::ShowNotification(const QString& title,
|
||||
const QString& description) {
|
||||
auto* notification =
|
||||
@@ -384,14 +332,16 @@ void PerformanceTuningDialogQt::ShowNotification(const QString& title,
|
||||
void PerformanceTuningDialogQt::OnVsyncChanged(int state) {
|
||||
bool enabled = (state == Qt::Checked);
|
||||
SetVsync(enabled);
|
||||
SaveToGameConfig("vsync", enabled);
|
||||
config::SaveGameConfigSetting(emulator_window_->emulator(), "GPU", "vsync",
|
||||
enabled);
|
||||
ShowNotification("VSync", enabled ? "Enabled" : "Disabled");
|
||||
}
|
||||
|
||||
void PerformanceTuningDialogQt::OnOcclusionQueryChanged(int state) {
|
||||
bool enabled = (state == Qt::Checked);
|
||||
SetOcclusionQueryEnable(enabled);
|
||||
SaveToGameConfig("occlusion_query_enable", enabled);
|
||||
config::SaveGameConfigSetting(emulator_window_->emulator(), "GPU",
|
||||
"occlusion_query_enable", enabled);
|
||||
ShowNotification("Occlusion Queries", enabled ? "Enabled" : "Disabled");
|
||||
}
|
||||
|
||||
@@ -447,8 +397,10 @@ void PerformanceTuningDialogQt::OnReadbackMemexportChanged(int value) {
|
||||
|
||||
gpu::SaveGPUSetting(gpu::GPUSetting::ReadbackMemexport, memexport_enabled);
|
||||
gpu::SaveGPUSetting(gpu::GPUSetting::ReadbackMemexportFast, memexport_fast);
|
||||
SaveToGameConfig("readback_memexport", memexport_enabled);
|
||||
SaveToGameConfig("readback_memexport_fast", memexport_fast);
|
||||
config::SaveGameConfigSetting(emulator_window_->emulator(), "GPU",
|
||||
"readback_memexport", memexport_enabled);
|
||||
config::SaveGameConfigSetting(emulator_window_->emulator(), "GPU",
|
||||
"readback_memexport_fast", memexport_fast);
|
||||
|
||||
const char* mode_names[] = {"None", "Fast", "Full"};
|
||||
ShowNotification("Readback Memexport", mode_names[value]);
|
||||
@@ -457,7 +409,8 @@ void PerformanceTuningDialogQt::OnReadbackMemexportChanged(int value) {
|
||||
void PerformanceTuningDialogQt::OnClearMemoryPageStateChanged(int state) {
|
||||
bool enabled = (state == Qt::Checked);
|
||||
gpu::SaveGPUSetting(gpu::GPUSetting::ClearMemoryPageState, enabled);
|
||||
SaveToGameConfig("clear_memory_page_state", enabled);
|
||||
config::SaveGameConfigSetting(emulator_window_->emulator(), "GPU",
|
||||
"clear_memory_page_state", enabled);
|
||||
ShowNotification("Clear Memory Page State", enabled ? "Enabled" : "Disabled");
|
||||
}
|
||||
|
||||
|
||||
@@ -49,8 +49,6 @@ class PerformanceTuningDialogQt : public ui::GamepadDialog {
|
||||
private:
|
||||
void SetupUI();
|
||||
void LoadCurrentSettings();
|
||||
void SaveToGameConfig(const char* cvar_name, const std::string& value);
|
||||
void SaveToGameConfig(const char* cvar_name, bool value);
|
||||
void ShowNotification(const QString& title, const QString& description);
|
||||
|
||||
EmulatorWindow* emulator_window_;
|
||||
|
||||
@@ -20,12 +20,14 @@
|
||||
#include "third_party/fmt/include/fmt/format.h"
|
||||
#include "xenia/app/emulator_window.h"
|
||||
#include "xenia/base/cvar.h"
|
||||
#include "xenia/config.h"
|
||||
#include "xenia/gpu/graphics_system.h"
|
||||
#include "xenia/ui/qt_util.h"
|
||||
|
||||
DECLARE_bool(postprocess_dither);
|
||||
DECLARE_double(postprocess_ffx_cas_additional_sharpness);
|
||||
DECLARE_double(postprocess_ffx_fsr_sharpness_reduction);
|
||||
DECLARE_uint32(postprocess_ffx_fsr_max_upsampling_passes);
|
||||
DECLARE_string(postprocess_antialiasing);
|
||||
DECLARE_string(postprocess_scaling_and_sharpening);
|
||||
|
||||
@@ -210,32 +212,162 @@ void PostProcessingDialogQt::SetupUI() {
|
||||
resampling_layout->setSpacing(8);
|
||||
|
||||
resampling_button_group_ = new QButtonGroup(this);
|
||||
|
||||
// None / Bilinear option (no controls)
|
||||
effect_bilinear_radio_ =
|
||||
new QRadioButton("None / Bilinear", resampling_group_);
|
||||
effect_cas_radio_ = new QRadioButton(
|
||||
"AMD FidelityFX Contrast Adaptive Sharpening (CAS)", resampling_group_);
|
||||
effect_fsr_radio_ = new QRadioButton(
|
||||
"AMD FidelityFX Super Resolution 1.0 (FSR)", resampling_group_);
|
||||
|
||||
resampling_button_group_->addButton(
|
||||
effect_bilinear_radio_,
|
||||
static_cast<int>(
|
||||
ui::Presenter::GuestOutputPaintConfig::Effect::kBilinear));
|
||||
resampling_layout->addWidget(effect_bilinear_radio_);
|
||||
|
||||
// CAS option with controls as children
|
||||
auto* cas_container = new QWidget(resampling_group_);
|
||||
auto* cas_container_layout = new QVBoxLayout(cas_container);
|
||||
cas_container_layout->setContentsMargins(0, 0, 0, 0);
|
||||
cas_container_layout->setSpacing(4);
|
||||
|
||||
effect_cas_radio_ = new QRadioButton(
|
||||
"AMD FidelityFX Contrast Adaptive Sharpening (CAS)", cas_container);
|
||||
resampling_button_group_->addButton(
|
||||
effect_cas_radio_,
|
||||
static_cast<int>(ui::Presenter::GuestOutputPaintConfig::Effect::kCas));
|
||||
cas_container_layout->addWidget(effect_cas_radio_);
|
||||
|
||||
// CAS controls as children of cas_container
|
||||
cas_sharpness_widget_ = new QWidget(cas_container);
|
||||
auto* cas_layout = new QVBoxLayout(cas_sharpness_widget_);
|
||||
cas_layout->setContentsMargins(20, 4, 0, 0);
|
||||
|
||||
cas_sharpness_label_ = new QLabel(
|
||||
"CAS additional sharpness (higher is sharper):", cas_sharpness_widget_);
|
||||
cas_layout->addWidget(cas_sharpness_label_);
|
||||
|
||||
auto* cas_slider_layout = new QHBoxLayout();
|
||||
cas_sharpness_slider_ = new QSlider(Qt::Horizontal, cas_sharpness_widget_);
|
||||
cas_sharpness_slider_->setRange(0, 100); // Will be mapped to 0.0-1.0
|
||||
cas_sharpness_slider_->setFocusPolicy(Qt::StrongFocus);
|
||||
cas_sharpness_value_label_ = new QLabel("0%", cas_sharpness_widget_);
|
||||
cas_sharpness_value_label_->setMinimumWidth(50);
|
||||
cas_reset_button_ = new QPushButton("Reset", cas_sharpness_widget_);
|
||||
cas_reset_button_->setMaximumWidth(50);
|
||||
cas_reset_button_->setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
cas_slider_layout->addWidget(cas_sharpness_slider_);
|
||||
cas_slider_layout->addWidget(cas_sharpness_value_label_);
|
||||
cas_slider_layout->addWidget(cas_reset_button_);
|
||||
cas_layout->addLayout(cas_slider_layout);
|
||||
|
||||
cas_container_layout->addWidget(cas_sharpness_widget_);
|
||||
resampling_layout->addWidget(cas_container);
|
||||
|
||||
// FSR option with controls as children
|
||||
auto* fsr_container = new QWidget(resampling_group_);
|
||||
auto* fsr_container_layout = new QVBoxLayout(fsr_container);
|
||||
fsr_container_layout->setContentsMargins(0, 0, 0, 0);
|
||||
fsr_container_layout->setSpacing(4);
|
||||
|
||||
effect_fsr_radio_ = new QRadioButton(
|
||||
"AMD FidelityFX Super Resolution 1.0 (FSR)", fsr_container);
|
||||
resampling_button_group_->addButton(
|
||||
effect_fsr_radio_,
|
||||
static_cast<int>(ui::Presenter::GuestOutputPaintConfig::Effect::kFsr));
|
||||
fsr_container_layout->addWidget(effect_fsr_radio_);
|
||||
|
||||
resampling_layout->addWidget(effect_bilinear_radio_);
|
||||
resampling_layout->addWidget(effect_cas_radio_);
|
||||
resampling_layout->addWidget(effect_fsr_radio_);
|
||||
// FSR sharpness controls as children of fsr_container
|
||||
fsr_sharpness_widget_ = new QWidget(fsr_container);
|
||||
auto* fsr_layout = new QVBoxLayout(fsr_sharpness_widget_);
|
||||
fsr_layout->setContentsMargins(20, 4, 0, 0);
|
||||
|
||||
fsr_sharpness_label_ =
|
||||
new QLabel("FSR sharpness reduction when upscaling (lower is sharper):",
|
||||
fsr_sharpness_widget_);
|
||||
fsr_layout->addWidget(fsr_sharpness_label_);
|
||||
|
||||
auto* fsr_slider_layout = new QHBoxLayout();
|
||||
fsr_sharpness_slider_ = new QSlider(Qt::Horizontal, fsr_sharpness_widget_);
|
||||
fsr_sharpness_slider_->setRange(0, 200); // Will be mapped to 0.0-2.0
|
||||
fsr_sharpness_slider_->setFocusPolicy(Qt::StrongFocus);
|
||||
fsr_sharpness_value_label_ = new QLabel("0%", fsr_sharpness_widget_);
|
||||
fsr_sharpness_value_label_->setMinimumWidth(50);
|
||||
fsr_reset_button_ = new QPushButton("Reset", fsr_sharpness_widget_);
|
||||
fsr_reset_button_->setMaximumWidth(50);
|
||||
fsr_reset_button_->setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
fsr_slider_layout->addWidget(fsr_sharpness_slider_);
|
||||
fsr_slider_layout->addWidget(fsr_sharpness_value_label_);
|
||||
fsr_slider_layout->addWidget(fsr_reset_button_);
|
||||
fsr_layout->addLayout(fsr_slider_layout);
|
||||
|
||||
fsr_container_layout->addWidget(fsr_sharpness_widget_);
|
||||
|
||||
// FSR max upsampling controls as children of fsr_container
|
||||
fsr_max_upsampling_widget_ = new QWidget(fsr_container);
|
||||
auto* fsr_upsampling_layout = new QVBoxLayout(fsr_max_upsampling_widget_);
|
||||
fsr_upsampling_layout->setContentsMargins(20, 4, 0, 0);
|
||||
|
||||
fsr_max_upsampling_label_ = new QLabel(
|
||||
"FSR max upsampling passes (lower is faster, higher is better quality):",
|
||||
fsr_max_upsampling_widget_);
|
||||
fsr_upsampling_layout->addWidget(fsr_max_upsampling_label_);
|
||||
|
||||
fsr_max_upsampling_button_group_ = new QButtonGroup(this);
|
||||
fsr_max_upsampling_radio_1_ =
|
||||
new QRadioButton("1", fsr_max_upsampling_widget_);
|
||||
fsr_max_upsampling_radio_1_->setFocusPolicy(Qt::StrongFocus);
|
||||
fsr_max_upsampling_radio_2_ =
|
||||
new QRadioButton("2", fsr_max_upsampling_widget_);
|
||||
fsr_max_upsampling_radio_2_->setFocusPolicy(Qt::StrongFocus);
|
||||
fsr_max_upsampling_radio_3_ =
|
||||
new QRadioButton("3", fsr_max_upsampling_widget_);
|
||||
fsr_max_upsampling_radio_3_->setFocusPolicy(Qt::StrongFocus);
|
||||
fsr_max_upsampling_radio_4_ =
|
||||
new QRadioButton("4", fsr_max_upsampling_widget_);
|
||||
fsr_max_upsampling_radio_4_->setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
fsr_max_upsampling_button_group_->addButton(fsr_max_upsampling_radio_1_, 1);
|
||||
fsr_max_upsampling_button_group_->addButton(fsr_max_upsampling_radio_2_, 2);
|
||||
fsr_max_upsampling_button_group_->addButton(fsr_max_upsampling_radio_3_, 3);
|
||||
fsr_max_upsampling_button_group_->addButton(fsr_max_upsampling_radio_4_, 4);
|
||||
|
||||
auto* fsr_upsampling_radio_layout = new QHBoxLayout();
|
||||
fsr_upsampling_radio_layout->addWidget(fsr_max_upsampling_radio_1_);
|
||||
fsr_upsampling_radio_layout->addWidget(fsr_max_upsampling_radio_2_);
|
||||
fsr_upsampling_radio_layout->addWidget(fsr_max_upsampling_radio_3_);
|
||||
fsr_upsampling_radio_layout->addWidget(fsr_max_upsampling_radio_4_);
|
||||
fsr_max_upsampling_reset_button_ =
|
||||
new QPushButton("Reset", fsr_max_upsampling_widget_);
|
||||
fsr_max_upsampling_reset_button_->setMaximumWidth(50);
|
||||
fsr_max_upsampling_reset_button_->setFocusPolicy(Qt::StrongFocus);
|
||||
fsr_upsampling_radio_layout->addWidget(fsr_max_upsampling_reset_button_);
|
||||
|
||||
fsr_upsampling_layout->addLayout(fsr_upsampling_radio_layout);
|
||||
fsr_container_layout->addWidget(fsr_max_upsampling_widget_);
|
||||
|
||||
resampling_layout->addWidget(fsr_container);
|
||||
|
||||
connect(resampling_button_group_,
|
||||
QOverload<int>::of(&QButtonGroup::idClicked), this,
|
||||
&PostProcessingDialogQt::OnResamplingEffectChanged);
|
||||
|
||||
// Connect all the signal handlers
|
||||
connect(fsr_sharpness_slider_, &QSlider::valueChanged, this,
|
||||
&PostProcessingDialogQt::OnFsrSharpnessChanged);
|
||||
connect(fsr_reset_button_, &QPushButton::clicked, this,
|
||||
&PostProcessingDialogQt::OnResetFsrSharpness);
|
||||
|
||||
connect(fsr_max_upsampling_button_group_,
|
||||
QOverload<int>::of(&QButtonGroup::idClicked), this,
|
||||
&PostProcessingDialogQt::OnFsrMaxUpsamplingPassesChanged);
|
||||
connect(fsr_max_upsampling_reset_button_, &QPushButton::clicked, this,
|
||||
&PostProcessingDialogQt::OnResetFsrMaxUpsamplingPasses);
|
||||
|
||||
connect(cas_sharpness_slider_, &QSlider::valueChanged, this,
|
||||
&PostProcessingDialogQt::OnCasSharpnessChanged);
|
||||
connect(cas_reset_button_, &QPushButton::clicked, this,
|
||||
&PostProcessingDialogQt::OnResetCasSharpness);
|
||||
|
||||
// Effect description
|
||||
effect_description_label_ = new QLabel(resampling_group_);
|
||||
effect_description_label_->setWordWrap(true);
|
||||
@@ -251,63 +383,6 @@ void PostProcessingDialogQt::SetupUI() {
|
||||
"QLabel { margin-top: 10px; color: #aad4ff; font-weight: bold; }");
|
||||
resampling_layout->addWidget(fxaa_recommendation_label_);
|
||||
|
||||
// FSR sharpness controls
|
||||
fsr_sharpness_widget_ = new QWidget(resampling_group_);
|
||||
auto* fsr_layout = new QVBoxLayout(fsr_sharpness_widget_);
|
||||
fsr_layout->setContentsMargins(0, 10, 0, 0);
|
||||
|
||||
fsr_sharpness_label_ =
|
||||
new QLabel("FSR sharpness reduction when upscaling (lower is sharper):",
|
||||
fsr_sharpness_widget_);
|
||||
fsr_layout->addWidget(fsr_sharpness_label_);
|
||||
|
||||
auto* fsr_slider_layout = new QHBoxLayout();
|
||||
fsr_sharpness_slider_ = new QSlider(Qt::Horizontal, fsr_sharpness_widget_);
|
||||
fsr_sharpness_slider_->setRange(0, 200); // Will be mapped to 0.0-2.0
|
||||
fsr_sharpness_value_label_ = new QLabel("0%", fsr_sharpness_widget_);
|
||||
fsr_sharpness_value_label_->setMinimumWidth(50);
|
||||
fsr_reset_button_ = new QPushButton("Reset", fsr_sharpness_widget_);
|
||||
|
||||
fsr_slider_layout->addWidget(fsr_sharpness_slider_);
|
||||
fsr_slider_layout->addWidget(fsr_sharpness_value_label_);
|
||||
fsr_slider_layout->addWidget(fsr_reset_button_);
|
||||
fsr_layout->addLayout(fsr_slider_layout);
|
||||
|
||||
connect(fsr_sharpness_slider_, &QSlider::valueChanged, this,
|
||||
&PostProcessingDialogQt::OnFsrSharpnessChanged);
|
||||
connect(fsr_reset_button_, &QPushButton::clicked, this,
|
||||
&PostProcessingDialogQt::OnResetFsrSharpness);
|
||||
|
||||
resampling_layout->addWidget(fsr_sharpness_widget_);
|
||||
|
||||
// CAS sharpness controls
|
||||
cas_sharpness_widget_ = new QWidget(resampling_group_);
|
||||
auto* cas_layout = new QVBoxLayout(cas_sharpness_widget_);
|
||||
cas_layout->setContentsMargins(0, 10, 0, 0);
|
||||
|
||||
cas_sharpness_label_ = new QLabel(
|
||||
"CAS additional sharpness (higher is sharper):", cas_sharpness_widget_);
|
||||
cas_layout->addWidget(cas_sharpness_label_);
|
||||
|
||||
auto* cas_slider_layout = new QHBoxLayout();
|
||||
cas_sharpness_slider_ = new QSlider(Qt::Horizontal, cas_sharpness_widget_);
|
||||
cas_sharpness_slider_->setRange(0, 100); // Will be mapped to 0.0-1.0
|
||||
cas_sharpness_value_label_ = new QLabel("0%", cas_sharpness_widget_);
|
||||
cas_sharpness_value_label_->setMinimumWidth(50);
|
||||
cas_reset_button_ = new QPushButton("Reset", cas_sharpness_widget_);
|
||||
|
||||
cas_slider_layout->addWidget(cas_sharpness_slider_);
|
||||
cas_slider_layout->addWidget(cas_sharpness_value_label_);
|
||||
cas_slider_layout->addWidget(cas_reset_button_);
|
||||
cas_layout->addLayout(cas_slider_layout);
|
||||
|
||||
connect(cas_sharpness_slider_, &QSlider::valueChanged, this,
|
||||
&PostProcessingDialogQt::OnCasSharpnessChanged);
|
||||
connect(cas_reset_button_, &QPushButton::clicked, this,
|
||||
&PostProcessingDialogQt::OnResetCasSharpness);
|
||||
|
||||
resampling_layout->addWidget(cas_sharpness_widget_);
|
||||
|
||||
content_layout->addWidget(resampling_group_);
|
||||
|
||||
// Dithering group
|
||||
@@ -339,6 +414,14 @@ void PostProcessingDialogQt::LoadCurrentSettings() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Block signals while loading to prevent triggering save handlers
|
||||
aa_button_group_->blockSignals(true);
|
||||
resampling_button_group_->blockSignals(true);
|
||||
fsr_sharpness_slider_->blockSignals(true);
|
||||
fsr_max_upsampling_button_group_->blockSignals(true);
|
||||
cas_sharpness_slider_->blockSignals(true);
|
||||
dither_checkbox_->blockSignals(true);
|
||||
|
||||
// Load anti-aliasing settings
|
||||
auto command_processor = graphics_system->command_processor();
|
||||
if (command_processor) {
|
||||
@@ -357,18 +440,41 @@ void PostProcessingDialogQt::LoadCurrentSettings() {
|
||||
|
||||
// Set FSR sharpness (convert from 0.0-2.0 to 0-200)
|
||||
float fsr_sharpness = config.GetFsrSharpnessReduction();
|
||||
// Apply power 2.0 scaling as done in ImGui version
|
||||
fsr_sharpness = sqrt(2.f * fsr_sharpness);
|
||||
fsr_sharpness_slider_->setValue(static_cast<int>(fsr_sharpness * 100));
|
||||
// Apply power 2.0 scaling as done in ImGui version for slider position
|
||||
float slider_position = sqrt(2.f * fsr_sharpness);
|
||||
fsr_sharpness_slider_->setValue(static_cast<int>(slider_position * 100));
|
||||
// Update label to show actual FSR sharpness percentage
|
||||
fsr_sharpness_value_label_->setText(SafeQString(
|
||||
fmt::format("{} %", static_cast<int>(fsr_sharpness * 100))));
|
||||
|
||||
// Set FSR max upsampling passes
|
||||
uint32_t fsr_max_upsampling = config.GetFsrMaxUpsamplingPasses();
|
||||
// Clamp to valid range 1-4
|
||||
fsr_max_upsampling =
|
||||
std::max(uint32_t(1), std::min(uint32_t(4), fsr_max_upsampling));
|
||||
fsr_max_upsampling_button_group_
|
||||
->button(static_cast<int>(fsr_max_upsampling))
|
||||
->setChecked(true);
|
||||
|
||||
// Set CAS sharpness (convert from 0.0-1.0 to 0-100)
|
||||
float cas_sharpness = config.GetCasAdditionalSharpness();
|
||||
cas_sharpness_slider_->setValue(static_cast<int>(cas_sharpness * 100));
|
||||
// Update label to match slider value
|
||||
cas_sharpness_value_label_->setText(SafeQString(
|
||||
fmt::format("{} %", static_cast<int>(cas_sharpness * 100))));
|
||||
|
||||
// Set dithering
|
||||
dither_checkbox_->setChecked(config.GetDither());
|
||||
}
|
||||
|
||||
// Re-enable signals
|
||||
aa_button_group_->blockSignals(false);
|
||||
resampling_button_group_->blockSignals(false);
|
||||
fsr_sharpness_slider_->blockSignals(false);
|
||||
fsr_max_upsampling_button_group_->blockSignals(false);
|
||||
cas_sharpness_slider_->blockSignals(false);
|
||||
dither_checkbox_->blockSignals(false);
|
||||
|
||||
UpdateEffectDescription();
|
||||
UpdateSharpnessControls();
|
||||
}
|
||||
@@ -394,6 +500,12 @@ void PostProcessingDialogQt::OnAntiAliasingChanged(int index) {
|
||||
|
||||
// Update cvar
|
||||
emulator_window_->UpdateAntiAliasingCvar(new_effect);
|
||||
|
||||
// Save to game config
|
||||
const char* effect_str =
|
||||
EmulatorWindow::GetCvarValueForSwapPostEffect(new_effect);
|
||||
config::SaveGameConfigSetting(emulator, "Display", "postprocess_antialiasing",
|
||||
std::string(effect_str));
|
||||
}
|
||||
|
||||
void PostProcessingDialogQt::OnResamplingEffectChanged(int index) {
|
||||
@@ -421,6 +533,13 @@ void PostProcessingDialogQt::OnResamplingEffectChanged(int index) {
|
||||
// Update cvar
|
||||
emulator_window_->UpdateScalingAndSharpeningCvar(new_effect);
|
||||
|
||||
// Save to game config
|
||||
const char* effect_str =
|
||||
EmulatorWindow::GetCvarValueForGuestOutputPaintEffect(new_effect);
|
||||
config::SaveGameConfigSetting(emulator, "Display",
|
||||
"postprocess_scaling_and_sharpening",
|
||||
std::string(effect_str));
|
||||
|
||||
UpdateEffectDescription();
|
||||
UpdateSharpnessControls();
|
||||
}
|
||||
@@ -456,6 +575,11 @@ void PostProcessingDialogQt::OnFsrSharpnessChanged(int value) {
|
||||
|
||||
// Update cvar
|
||||
emulator_window_->UpdateFsrSharpnessCvar(fsr_sharpness);
|
||||
|
||||
// Save to game config
|
||||
config::SaveGameConfigSetting(emulator, "Display",
|
||||
"postprocess_ffx_fsr_sharpness_reduction",
|
||||
fsr_sharpness);
|
||||
}
|
||||
|
||||
void PostProcessingDialogQt::OnCasSharpnessChanged(int value) {
|
||||
@@ -487,6 +611,11 @@ void PostProcessingDialogQt::OnCasSharpnessChanged(int value) {
|
||||
|
||||
// Update cvar
|
||||
emulator_window_->UpdateCasSharpnessCvar(cas_sharpness);
|
||||
|
||||
// Save to game config
|
||||
config::SaveGameConfigSetting(emulator, "Display",
|
||||
"postprocess_ffx_cas_additional_sharpness",
|
||||
cas_sharpness);
|
||||
}
|
||||
|
||||
void PostProcessingDialogQt::OnDitherChanged(int state) {
|
||||
@@ -513,6 +642,10 @@ void PostProcessingDialogQt::OnDitherChanged(int state) {
|
||||
|
||||
// Update cvar
|
||||
emulator_window_->UpdateDitherCvar(dither);
|
||||
|
||||
// Save to game config
|
||||
config::SaveGameConfigSetting(emulator, "Display", "postprocess_dither",
|
||||
dither);
|
||||
}
|
||||
|
||||
void PostProcessingDialogQt::OnResetFsrSharpness() {
|
||||
@@ -530,6 +663,45 @@ void PostProcessingDialogQt::OnResetCasSharpness() {
|
||||
cas_sharpness_slider_->setValue(static_cast<int>(default_value * 100));
|
||||
}
|
||||
|
||||
void PostProcessingDialogQt::OnFsrMaxUpsamplingPassesChanged(int value) {
|
||||
auto emulator = emulator_window_->emulator();
|
||||
if (!emulator) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto graphics_system = emulator->graphics_system();
|
||||
if (!graphics_system) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto presenter = graphics_system->presenter();
|
||||
if (!presenter) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert slider value (1-8) to FSR max upsampling passes
|
||||
uint32_t max_upsampling_passes = static_cast<uint32_t>(value);
|
||||
|
||||
auto config = presenter->GetGuestOutputPaintConfigFromUIThread();
|
||||
config.SetFsrMaxUpsamplingPasses(max_upsampling_passes);
|
||||
presenter->SetGuestOutputPaintConfigFromUIThread(config);
|
||||
|
||||
// Update cvar
|
||||
emulator_window_->UpdateFsrMaxUpsamplingPassesCvar(max_upsampling_passes);
|
||||
|
||||
// Save to game config
|
||||
config::SaveGameConfigSetting(emulator, "Display",
|
||||
"postprocess_ffx_fsr_max_upsampling_passes",
|
||||
max_upsampling_passes);
|
||||
}
|
||||
|
||||
void PostProcessingDialogQt::OnResetFsrMaxUpsamplingPasses() {
|
||||
uint32_t default_value =
|
||||
ui::Presenter::GuestOutputPaintConfig::kFsrMaxUpscalingPassesMax;
|
||||
fsr_max_upsampling_button_group_->button(static_cast<int>(default_value))
|
||||
->setChecked(true);
|
||||
}
|
||||
|
||||
void PostProcessingDialogQt::UpdateEffectDescription() {
|
||||
auto emulator = emulator_window_->emulator();
|
||||
if (!emulator) {
|
||||
@@ -607,23 +779,22 @@ void PostProcessingDialogQt::UpdateSharpnessControls() {
|
||||
// Show/hide FXAA recommendation
|
||||
fxaa_recommendation_label_->setVisible(is_cas || is_fsr);
|
||||
|
||||
// Show/hide FSR sharpness controls
|
||||
// With the new widget hierarchy, we can simply show/hide the control widgets
|
||||
fsr_sharpness_widget_->setVisible(is_fsr);
|
||||
fsr_max_upsampling_widget_->setVisible(is_fsr);
|
||||
cas_sharpness_widget_->setVisible(is_cas);
|
||||
|
||||
// Show/hide CAS sharpness controls
|
||||
cas_sharpness_widget_->setVisible(is_cas || is_fsr);
|
||||
|
||||
// Update CAS label text based on effect
|
||||
if (is_fsr) {
|
||||
cas_sharpness_label_->setText(
|
||||
"CAS additional sharpness when not upscaling (higher is sharper):");
|
||||
} else {
|
||||
// CAS label text (only shown for pure CAS, not FSR)
|
||||
if (is_cas) {
|
||||
cas_sharpness_label_->setText(
|
||||
"CAS additional sharpness (higher is sharper):");
|
||||
}
|
||||
|
||||
// Resize dialog to fit content after showing/hiding widgets
|
||||
adjustSize();
|
||||
|
||||
// Update the list of focusable widgets since visibility has changed
|
||||
UpdateFocusableWidgets();
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
||||
@@ -41,9 +41,11 @@ class PostProcessingDialogQt : public ui::GamepadDialog {
|
||||
void OnResamplingEffectChanged(int index);
|
||||
void OnFsrSharpnessChanged(int value);
|
||||
void OnCasSharpnessChanged(int value);
|
||||
void OnFsrMaxUpsamplingPassesChanged(int value);
|
||||
void OnDitherChanged(int state);
|
||||
void OnResetFsrSharpness();
|
||||
void OnResetCasSharpness();
|
||||
void OnResetFsrMaxUpsamplingPasses();
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
@@ -89,6 +91,16 @@ class PostProcessingDialogQt : public ui::GamepadDialog {
|
||||
QLabel* cas_sharpness_value_label_;
|
||||
QPushButton* cas_reset_button_;
|
||||
|
||||
// FSR max upsampling passes widgets
|
||||
QWidget* fsr_max_upsampling_widget_;
|
||||
QLabel* fsr_max_upsampling_label_;
|
||||
QButtonGroup* fsr_max_upsampling_button_group_;
|
||||
QRadioButton* fsr_max_upsampling_radio_1_;
|
||||
QRadioButton* fsr_max_upsampling_radio_2_;
|
||||
QRadioButton* fsr_max_upsampling_radio_3_;
|
||||
QRadioButton* fsr_max_upsampling_radio_4_;
|
||||
QPushButton* fsr_max_upsampling_reset_button_;
|
||||
|
||||
// Dithering widgets
|
||||
QGroupBox* dither_group_;
|
||||
QCheckBox* dither_checkbox_;
|
||||
|
||||
Reference in New Issue
Block a user