// Copyright 2017 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "DolphinQt/Config/Graphics/EnhancementsWidget.h" #include #include #include #include #include #include #include "Core/Config/GraphicsSettings.h" #include "Core/ConfigManager.h" #include "DolphinQt/Config/ConfigControls/ConfigBool.h" #include "DolphinQt/Config/ConfigControls/ConfigChoice.h" #include "DolphinQt/Config/ConfigControls/ConfigRadio.h" #include "DolphinQt/Config/ConfigControls/ConfigSlider.h" #include "DolphinQt/Config/Graphics/ColorCorrectionConfigWindow.h" #include "DolphinQt/Config/Graphics/GraphicsWindow.h" #include "DolphinQt/Config/Graphics/PostProcessingConfigWindow.h" #include "DolphinQt/Config/ToolTipControls/ToolTipPushButton.h" #include "DolphinQt/QtUtils/NonDefaultQPushButton.h" #include "DolphinQt/QtUtils/SetWindowDecorations.h" #include "DolphinQt/Settings.h" #include "VideoCommon/PostProcessing.h" #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoConfig.h" EnhancementsWidget::EnhancementsWidget(GraphicsWindow* parent) : m_block_save(false) { CreateWidgets(); LoadSettings(); ConnectWidgets(); AddDescriptions(); connect(parent, &GraphicsWindow::BackendChanged, [this](const QString& backend) { LoadSettings(); }); connect(parent, &GraphicsWindow::UseFastTextureSamplingChanged, this, &EnhancementsWidget::LoadSettings); connect(parent, &GraphicsWindow::UseGPUTextureDecodingChanged, this, &EnhancementsWidget::LoadSettings); } constexpr int TEXTURE_FILTERING_DEFAULT = 0; constexpr int TEXTURE_FILTERING_ANISO_2X = 1; constexpr int TEXTURE_FILTERING_ANISO_4X = 2; constexpr int TEXTURE_FILTERING_ANISO_8X = 3; constexpr int TEXTURE_FILTERING_ANISO_16X = 4; constexpr int TEXTURE_FILTERING_FORCE_NEAREST = 5; constexpr int TEXTURE_FILTERING_FORCE_LINEAR = 6; constexpr int TEXTURE_FILTERING_FORCE_LINEAR_ANISO_2X = 7; constexpr int TEXTURE_FILTERING_FORCE_LINEAR_ANISO_4X = 8; constexpr int TEXTURE_FILTERING_FORCE_LINEAR_ANISO_8X = 9; constexpr int TEXTURE_FILTERING_FORCE_LINEAR_ANISO_16X = 10; void EnhancementsWidget::CreateWidgets() { auto* main_layout = new QVBoxLayout; // Enhancements auto* enhancements_box = new QGroupBox(tr("Enhancements")); auto* enhancements_layout = new QGridLayout(); enhancements_box->setLayout(enhancements_layout); QStringList resolution_options{tr("Auto (Multiple of 640x528)"), tr("Native (640x528)")}; // From 2x up. // To calculate the suggested internal resolution scale for each common output resolution, // we find the minimum multiplier that results in an equal or greater resolution than the // output one, on both width and height. // Note that often games don't render to the full resolution, but have some black bars // on the edges; this is not accounted for in the calculations. const QStringList resolution_extra_options{ tr("720p"), tr("1080p"), tr("1440p"), QStringLiteral(""), tr("4K"), QStringLiteral(""), tr("5K"), QStringLiteral(""), QStringLiteral(""), QStringLiteral(""), tr("8K")}; const int visible_resolution_option_count = static_cast(resolution_options.size()) + static_cast(resolution_extra_options.size()); // If the current scale is greater than the max scale in the ini, add sufficient options so that // when the settings are saved we don't lose the user-modified value from the ini. const int max_efb_scale = std::max(Config::Get(Config::GFX_EFB_SCALE), Config::Get(Config::GFX_MAX_EFB_SCALE)); for (int scale = static_cast(resolution_options.size()); scale <= max_efb_scale; scale++) { const QString scale_text = QString::number(scale); const QString width_text = QString::number(static_cast(EFB_WIDTH) * scale); const QString height_text = QString::number(static_cast(EFB_HEIGHT) * scale); const int extra_index = resolution_options.size() - 2; const QString extra_text = resolution_extra_options.size() > extra_index ? resolution_extra_options[extra_index] : QStringLiteral(""); if (extra_text.isEmpty()) { resolution_options.append(tr("%1x Native (%2x%3)").arg(scale_text, width_text, height_text)); } else { resolution_options.append( tr("%1x Native (%2x%3) for %4").arg(scale_text, width_text, height_text, extra_text)); } } m_ir_combo = new ConfigChoice(resolution_options, Config::GFX_EFB_SCALE); m_ir_combo->setMaxVisibleItems(visible_resolution_option_count); m_aa_combo = new ToolTipComboBox(); m_texture_filtering_combo = new ToolTipComboBox(); m_texture_filtering_combo->addItem(tr("Default"), TEXTURE_FILTERING_DEFAULT); m_texture_filtering_combo->addItem(tr("2x Anisotropic"), TEXTURE_FILTERING_ANISO_2X); m_texture_filtering_combo->addItem(tr("4x Anisotropic"), TEXTURE_FILTERING_ANISO_4X); m_texture_filtering_combo->addItem(tr("8x Anisotropic"), TEXTURE_FILTERING_ANISO_8X); m_texture_filtering_combo->addItem(tr("16x Anisotropic"), TEXTURE_FILTERING_ANISO_16X); m_texture_filtering_combo->addItem(tr("Force Nearest"), TEXTURE_FILTERING_FORCE_NEAREST); m_texture_filtering_combo->addItem(tr("Force Linear"), TEXTURE_FILTERING_FORCE_LINEAR); m_texture_filtering_combo->addItem(tr("Force Linear and 2x Anisotropic"), TEXTURE_FILTERING_FORCE_LINEAR_ANISO_2X); m_texture_filtering_combo->addItem(tr("Force Linear and 4x Anisotropic"), TEXTURE_FILTERING_FORCE_LINEAR_ANISO_4X); m_texture_filtering_combo->addItem(tr("Force Linear and 8x Anisotropic"), TEXTURE_FILTERING_FORCE_LINEAR_ANISO_8X); m_texture_filtering_combo->addItem(tr("Force Linear and 16x Anisotropic"), TEXTURE_FILTERING_FORCE_LINEAR_ANISO_16X); m_output_resampling_combo = new ToolTipComboBox(); m_output_resampling_combo->addItem(tr("Default"), static_cast(OutputResamplingMode::Default)); m_output_resampling_combo->addItem(tr("Bilinear"), static_cast(OutputResamplingMode::Bilinear)); m_output_resampling_combo->addItem(tr("Bicubic: B-Spline"), static_cast(OutputResamplingMode::BSpline)); m_output_resampling_combo->addItem(tr("Bicubic: Mitchell-Netravali"), static_cast(OutputResamplingMode::MitchellNetravali)); m_output_resampling_combo->addItem(tr("Bicubic: Catmull-Rom"), static_cast(OutputResamplingMode::CatmullRom)); m_output_resampling_combo->addItem(tr("Sharp Bilinear"), static_cast(OutputResamplingMode::SharpBilinear)); m_output_resampling_combo->addItem(tr("Area Sampling"), static_cast(OutputResamplingMode::AreaSampling)); m_configure_color_correction = new ToolTipPushButton(tr("Configure")); m_pp_effect = new ToolTipComboBox(); m_configure_pp_effect = new NonDefaultQPushButton(tr("Configure")); m_scaled_efb_copy = new ConfigBool(tr("Scaled EFB Copy"), Config::GFX_HACK_COPY_EFB_SCALED); m_per_pixel_lighting = new ConfigBool(tr("Per-Pixel Lighting"), Config::GFX_ENABLE_PIXEL_LIGHTING); m_widescreen_hack = new ConfigBool(tr("Widescreen Hack"), Config::GFX_WIDESCREEN_HACK); m_disable_fog = new ConfigBool(tr("Disable Fog"), Config::GFX_DISABLE_FOG); m_force_24bit_color = new ConfigBool(tr("Force 24-Bit Color"), Config::GFX_ENHANCE_FORCE_TRUE_COLOR); m_disable_copy_filter = new ConfigBool(tr("Disable Copy Filter"), Config::GFX_ENHANCE_DISABLE_COPY_FILTER); m_arbitrary_mipmap_detection = new ConfigBool(tr("Arbitrary Mipmap Detection"), Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION); m_hdr = new ConfigBool(tr("HDR Post-Processing"), Config::GFX_ENHANCE_HDR_OUTPUT); int row = 0; enhancements_layout->addWidget(new QLabel(tr("Internal Resolution:")), row, 0); enhancements_layout->addWidget(m_ir_combo, row, 1, 1, -1); ++row; enhancements_layout->addWidget(new QLabel(tr("Anti-Aliasing:")), row, 0); enhancements_layout->addWidget(m_aa_combo, row, 1, 1, -1); ++row; enhancements_layout->addWidget(new QLabel(tr("Texture Filtering:")), row, 0); enhancements_layout->addWidget(m_texture_filtering_combo, row, 1, 1, -1); ++row; enhancements_layout->addWidget(new QLabel(tr("Output Resampling:")), row, 0); enhancements_layout->addWidget(m_output_resampling_combo, row, 1, 1, -1); ++row; enhancements_layout->addWidget(new QLabel(tr("Color Correction:")), row, 0); enhancements_layout->addWidget(m_configure_color_correction, row, 1, 1, -1); ++row; enhancements_layout->addWidget(new QLabel(tr("Post-Processing Effect:")), row, 0); enhancements_layout->addWidget(m_pp_effect, row, 1); enhancements_layout->addWidget(m_configure_pp_effect, row, 2); ++row; enhancements_layout->addWidget(m_scaled_efb_copy, row, 0); enhancements_layout->addWidget(m_per_pixel_lighting, row, 1, 1, -1); ++row; enhancements_layout->addWidget(m_widescreen_hack, row, 0); enhancements_layout->addWidget(m_force_24bit_color, row, 1, 1, -1); ++row; enhancements_layout->addWidget(m_disable_fog, row, 0); enhancements_layout->addWidget(m_arbitrary_mipmap_detection, row, 1, 1, -1); ++row; enhancements_layout->addWidget(m_disable_copy_filter, row, 0); enhancements_layout->addWidget(m_hdr, row, 1, 1, -1); ++row; // Stereoscopy auto* stereoscopy_box = new QGroupBox(tr("Stereoscopy")); auto* stereoscopy_layout = new QGridLayout(); stereoscopy_box->setLayout(stereoscopy_layout); m_3d_mode = new ConfigChoice({tr("Off"), tr("Side-by-Side"), tr("Top-and-Bottom"), tr("Anaglyph"), tr("HDMI 3D"), tr("Passive")}, Config::GFX_STEREO_MODE); m_3d_depth = new ConfigSlider(0, Config::GFX_STEREO_DEPTH_MAXIMUM, Config::GFX_STEREO_DEPTH); m_3d_convergence = new ConfigSlider(0, Config::GFX_STEREO_CONVERGENCE_MAXIMUM, Config::GFX_STEREO_CONVERGENCE, 100); m_3d_swap_eyes = new ConfigBool(tr("Swap Eyes"), Config::GFX_STEREO_SWAP_EYES); m_3d_per_eye_resolution = new ConfigBool(tr("Use Full Resolution Per Eye"), Config::GFX_STEREO_PER_EYE_RESOLUTION_FULL); stereoscopy_layout->addWidget(new QLabel(tr("Stereoscopic 3D Mode:")), 0, 0); stereoscopy_layout->addWidget(m_3d_mode, 0, 1); stereoscopy_layout->addWidget(new QLabel(tr("Depth:")), 1, 0); stereoscopy_layout->addWidget(m_3d_depth, 1, 1); stereoscopy_layout->addWidget(new QLabel(tr("Convergence:")), 2, 0); stereoscopy_layout->addWidget(m_3d_convergence, 2, 1); stereoscopy_layout->addWidget(m_3d_swap_eyes, 3, 0); stereoscopy_layout->addWidget(m_3d_per_eye_resolution, 4, 0); auto current_stereo_mode = Config::Get(Config::GFX_STEREO_MODE); if (current_stereo_mode != StereoMode::SBS && current_stereo_mode != StereoMode::TAB) m_3d_per_eye_resolution->hide(); main_layout->addWidget(enhancements_box); main_layout->addWidget(stereoscopy_box); main_layout->addStretch(); setLayout(main_layout); } void EnhancementsWidget::ConnectWidgets() { connect(m_aa_combo, &QComboBox::currentIndexChanged, [this](int) { SaveSettings(); }); connect(m_texture_filtering_combo, &QComboBox::currentIndexChanged, [this](int) { SaveSettings(); }); connect(m_output_resampling_combo, &QComboBox::currentIndexChanged, [this](int) { SaveSettings(); }); connect(m_pp_effect, &QComboBox::currentIndexChanged, [this](int) { SaveSettings(); }); connect(m_3d_mode, &QComboBox::currentIndexChanged, [this] { m_block_save = true; m_configure_color_correction->setEnabled(g_Config.backend_info.bSupportsPostProcessing); auto current_stereo_mode = Config::Get(Config::GFX_STEREO_MODE); LoadPPShaders(current_stereo_mode); if (current_stereo_mode == StereoMode::SBS || current_stereo_mode == StereoMode::TAB) m_3d_per_eye_resolution->show(); else m_3d_per_eye_resolution->hide(); m_block_save = false; SaveSettings(); }); connect(m_configure_color_correction, &QPushButton::clicked, this, &EnhancementsWidget::ConfigureColorCorrection); connect(m_configure_pp_effect, &QPushButton::clicked, this, &EnhancementsWidget::ConfigurePostProcessingShader); connect(&Settings::Instance(), &Settings::ConfigChanged, this, [this] { const QSignalBlocker blocker(this); m_block_save = true; LoadPPShaders(Config::Get(Config::GFX_STEREO_MODE)); m_block_save = false; }); } void EnhancementsWidget::LoadPPShaders(StereoMode stereo_mode) { std::vector shaders = VideoCommon::PostProcessing::GetShaderList(); if (stereo_mode == StereoMode::Anaglyph) { shaders = VideoCommon::PostProcessing::GetAnaglyphShaderList(); } else if (stereo_mode == StereoMode::Passive) { shaders = VideoCommon::PostProcessing::GetPassiveShaderList(); } m_pp_effect->clear(); if (stereo_mode != StereoMode::Anaglyph && stereo_mode != StereoMode::Passive) m_pp_effect->addItem(tr("(off)")); auto selected_shader = Config::Get(Config::GFX_ENHANCE_POST_SHADER); bool found = false; for (const auto& shader : shaders) { m_pp_effect->addItem(QString::fromStdString(shader)); if (selected_shader == shader) { m_pp_effect->setCurrentIndex(m_pp_effect->count() - 1); found = true; } } if (!found) { if (stereo_mode == StereoMode::Anaglyph) selected_shader = "dubois"; else if (stereo_mode == StereoMode::Passive) selected_shader = "horizontal"; else selected_shader = ""; int index = m_pp_effect->findText(QString::fromStdString(selected_shader)); if (index >= 0) m_pp_effect->setCurrentIndex(index); else m_pp_effect->setCurrentIndex(0); Config::SetBaseOrCurrent(Config::GFX_ENHANCE_POST_SHADER, selected_shader); } const bool supports_postprocessing = g_Config.backend_info.bSupportsPostProcessing; m_pp_effect->setEnabled(supports_postprocessing); m_pp_effect->setToolTip(supports_postprocessing ? QString{} : tr("%1 doesn't support this feature.") .arg(tr(g_video_backend->GetDisplayName().c_str()))); VideoCommon::PostProcessingConfiguration pp_shader; if (selected_shader != "" && supports_postprocessing) { pp_shader.LoadShader(selected_shader); m_configure_pp_effect->setEnabled(pp_shader.HasOptions()); } else { m_configure_pp_effect->setEnabled(false); } } void EnhancementsWidget::LoadSettings() { m_block_save = true; m_texture_filtering_combo->setEnabled(Config::Get(Config::GFX_HACK_FAST_TEXTURE_SAMPLING)); m_arbitrary_mipmap_detection->setEnabled(!Config::Get(Config::GFX_ENABLE_GPU_TEXTURE_DECODING)); // Anti-Aliasing const u32 aa_selection = Config::Get(Config::GFX_MSAA); const bool ssaa = Config::Get(Config::GFX_SSAA); const int aniso = Config::Get(Config::GFX_ENHANCE_MAX_ANISOTROPY); const TextureFilteringMode tex_filter_mode = Config::Get(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING); m_aa_combo->clear(); for (const u32 aa_mode : g_Config.backend_info.AAModes) { if (aa_mode == 1) m_aa_combo->addItem(tr("None"), 1); else m_aa_combo->addItem(tr("%1x MSAA").arg(aa_mode), static_cast(aa_mode)); if (aa_mode == aa_selection && !ssaa) m_aa_combo->setCurrentIndex(m_aa_combo->count() - 1); } if (g_Config.backend_info.bSupportsSSAA) { for (const u32 aa_mode : g_Config.backend_info.AAModes) { if (aa_mode != 1) // don't show "None" twice { // Mark SSAA using negative values in the variant m_aa_combo->addItem(tr("%1x SSAA").arg(aa_mode), -static_cast(aa_mode)); if (aa_mode == aa_selection && ssaa) m_aa_combo->setCurrentIndex(m_aa_combo->count() - 1); } } } m_aa_combo->setEnabled(m_aa_combo->count() > 1); switch (tex_filter_mode) { case TextureFilteringMode::Default: if (aniso >= 0 && aniso <= 4) m_texture_filtering_combo->setCurrentIndex(aniso); else m_texture_filtering_combo->setCurrentIndex(TEXTURE_FILTERING_DEFAULT); break; case TextureFilteringMode::Nearest: m_texture_filtering_combo->setCurrentIndex(TEXTURE_FILTERING_FORCE_NEAREST); break; case TextureFilteringMode::Linear: if (aniso >= 0 && aniso <= 4) m_texture_filtering_combo->setCurrentIndex(TEXTURE_FILTERING_FORCE_LINEAR + aniso); else m_texture_filtering_combo->setCurrentIndex(TEXTURE_FILTERING_FORCE_LINEAR); break; } // Resampling const OutputResamplingMode output_resampling_mode = Config::Get(Config::GFX_ENHANCE_OUTPUT_RESAMPLING); m_output_resampling_combo->setCurrentIndex( m_output_resampling_combo->findData(static_cast(output_resampling_mode))); m_output_resampling_combo->setEnabled(g_Config.backend_info.bSupportsPostProcessing); // Color Correction m_configure_color_correction->setEnabled(g_Config.backend_info.bSupportsPostProcessing); // Post Processing Shader LoadPPShaders(Config::Get(Config::GFX_STEREO_MODE)); // Stereoscopy const bool supports_stereoscopy = g_Config.backend_info.bSupportsGeometryShaders; m_3d_mode->setEnabled(supports_stereoscopy); m_3d_convergence->setEnabled(supports_stereoscopy); m_3d_depth->setEnabled(supports_stereoscopy); m_3d_swap_eyes->setEnabled(supports_stereoscopy); m_hdr->setEnabled(g_Config.backend_info.bSupportsHDROutput); m_block_save = false; } void EnhancementsWidget::SaveSettings() { if (m_block_save) return; const u32 aa_value = static_cast(std::abs(m_aa_combo->currentData().toInt())); const bool is_ssaa = m_aa_combo->currentData().toInt() < 0; Config::SetBaseOrCurrent(Config::GFX_MSAA, aa_value); Config::SetBaseOrCurrent(Config::GFX_SSAA, is_ssaa); const int texture_filtering_selection = m_texture_filtering_combo->currentData().toInt(); switch (texture_filtering_selection) { case TEXTURE_FILTERING_DEFAULT: Config::SetBaseOrCurrent(Config::GFX_ENHANCE_MAX_ANISOTROPY, 0); Config::SetBaseOrCurrent(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING, TextureFilteringMode::Default); break; case TEXTURE_FILTERING_ANISO_2X: Config::SetBaseOrCurrent(Config::GFX_ENHANCE_MAX_ANISOTROPY, 1); Config::SetBaseOrCurrent(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING, TextureFilteringMode::Default); break; case TEXTURE_FILTERING_ANISO_4X: Config::SetBaseOrCurrent(Config::GFX_ENHANCE_MAX_ANISOTROPY, 2); Config::SetBaseOrCurrent(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING, TextureFilteringMode::Default); break; case TEXTURE_FILTERING_ANISO_8X: Config::SetBaseOrCurrent(Config::GFX_ENHANCE_MAX_ANISOTROPY, 3); Config::SetBaseOrCurrent(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING, TextureFilteringMode::Default); break; case TEXTURE_FILTERING_ANISO_16X: Config::SetBaseOrCurrent(Config::GFX_ENHANCE_MAX_ANISOTROPY, 4); Config::SetBaseOrCurrent(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING, TextureFilteringMode::Default); break; case TEXTURE_FILTERING_FORCE_NEAREST: Config::SetBaseOrCurrent(Config::GFX_ENHANCE_MAX_ANISOTROPY, 0); Config::SetBaseOrCurrent(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING, TextureFilteringMode::Nearest); break; case TEXTURE_FILTERING_FORCE_LINEAR: Config::SetBaseOrCurrent(Config::GFX_ENHANCE_MAX_ANISOTROPY, 0); Config::SetBaseOrCurrent(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING, TextureFilteringMode::Linear); break; case TEXTURE_FILTERING_FORCE_LINEAR_ANISO_2X: Config::SetBaseOrCurrent(Config::GFX_ENHANCE_MAX_ANISOTROPY, 1); Config::SetBaseOrCurrent(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING, TextureFilteringMode::Linear); break; case TEXTURE_FILTERING_FORCE_LINEAR_ANISO_4X: Config::SetBaseOrCurrent(Config::GFX_ENHANCE_MAX_ANISOTROPY, 2); Config::SetBaseOrCurrent(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING, TextureFilteringMode::Linear); break; case TEXTURE_FILTERING_FORCE_LINEAR_ANISO_8X: Config::SetBaseOrCurrent(Config::GFX_ENHANCE_MAX_ANISOTROPY, 3); Config::SetBaseOrCurrent(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING, TextureFilteringMode::Linear); break; case TEXTURE_FILTERING_FORCE_LINEAR_ANISO_16X: Config::SetBaseOrCurrent(Config::GFX_ENHANCE_MAX_ANISOTROPY, 4); Config::SetBaseOrCurrent(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING, TextureFilteringMode::Linear); break; } const int output_resampling_selection = m_output_resampling_combo->currentData().toInt(); Config::SetBaseOrCurrent(Config::GFX_ENHANCE_OUTPUT_RESAMPLING, static_cast(output_resampling_selection)); const bool anaglyph = g_Config.stereo_mode == StereoMode::Anaglyph; const bool passive = g_Config.stereo_mode == StereoMode::Passive; Config::SetBaseOrCurrent(Config::GFX_ENHANCE_POST_SHADER, (!anaglyph && !passive && m_pp_effect->currentIndex() == 0) ? "" : m_pp_effect->currentText().toStdString()); VideoCommon::PostProcessingConfiguration pp_shader; if (Config::Get(Config::GFX_ENHANCE_POST_SHADER) != "") { pp_shader.LoadShader(Config::Get(Config::GFX_ENHANCE_POST_SHADER)); m_configure_pp_effect->setEnabled(pp_shader.HasOptions()); } else { m_configure_pp_effect->setEnabled(false); } LoadSettings(); } void EnhancementsWidget::AddDescriptions() { static const char TR_INTERNAL_RESOLUTION_DESCRIPTION[] = QT_TR_NOOP("Controls the rendering resolution.

A high resolution greatly improves " "visual quality, but also greatly increases GPU load and can cause issues in " "certain games. Generally speaking, the lower the internal resolution, the " "better performance will be.

If unsure, " "select Native."); static const char TR_ANTIALIAS_DESCRIPTION[] = QT_TR_NOOP( "Reduces the amount of aliasing caused by rasterizing 3D graphics, resulting " "in smoother edges on objects. Increases GPU load and sometimes causes graphical " "issues.

SSAA is significantly more demanding than MSAA, but provides top quality " "geometry anti-aliasing and also applies anti-aliasing to lighting, shader " "effects, and textures.

If unsure, select " "None."); static const char TR_FORCE_TEXTURE_FILTERING_DESCRIPTION[] = QT_TR_NOOP( "Adjust the texture filtering. Anisotropic filtering enhances the visual quality of textures " "that are at oblique viewing angles. Force Nearest and Force Linear override the texture " "scaling filter selected by the game.

Any option except 'Default' will alter the look " "of the game's textures and might cause issues in a small number of games.

This " "setting is disabled when Manual Texture Sampling is enabled.

" "If unsure, select 'Default'."); static const char TR_OUTPUT_RESAMPLING_DESCRIPTION[] = QT_TR_NOOP("Affects how the game output is scaled to the window resolution." "
The performance mostly depends on the number of samples each method uses." "
Compared to SSAA, resampling is useful in case the output window" "
resolution isn't a multiplier of the native emulation resolution." "

Default - [fastest]" "
Internal GPU bilinear sampler which is not gamma corrected." "
This setting might be ignored if gamma correction is forced on." "

Bilinear - [4 samples]" "
Gamma corrected linear interpolation between pixels." "

Bicubic - [16 samples]" "
Gamma corrected cubic interpolation between pixels." "
Good when rescaling between close resolutions, e.g. 1080p and 1440p." "
Comes in various flavors:" "
B-Spline: Blurry, but avoids all lobing artifacts" "
Mitchell-Netravali: Good middle ground between blurry and lobing" "
Catmull-Rom: Sharper, but can cause lobing artifacts" "

Sharp Bilinear - [1-4 samples]" "
Similar to \"Nearest Neighbor\", it maintains a sharp look," "
but also does some blending to avoid shimmering." "
Works best with 2D games at low resolutions." "

Area Sampling - [up to 324 samples]" "
Weighs pixels by the percentage of area they occupy. Gamma corrected." "
Best for downscaling by more than 2x." "

If unsure, select 'Default'."); static const char TR_COLOR_CORRECTION_DESCRIPTION[] = QT_TR_NOOP("A group of features to make the colors more accurate, matching the color space " "Wii and GC games were meant for."); static const char TR_POSTPROCESSING_DESCRIPTION[] = QT_TR_NOOP("Applies a post-processing effect after rendering a frame.

If unsure, select (off)."); static const char TR_SCALED_EFB_COPY_DESCRIPTION[] = QT_TR_NOOP("Greatly increases the quality of textures generated using render-to-texture " "effects.

Slightly increases GPU load and causes relatively few graphical " "issues. Raising the internal resolution will improve the effect of this setting. " "

If unsure, leave this checked."); static const char TR_PER_PIXEL_LIGHTING_DESCRIPTION[] = QT_TR_NOOP( "Calculates lighting of 3D objects per-pixel rather than per-vertex, smoothing out the " "appearance of lit polygons and making individual triangles less noticeable.

Rarely " "causes slowdowns or graphical issues.

If unsure, leave " "this unchecked."); static const char TR_WIDESCREEN_HACK_DESCRIPTION[] = QT_TR_NOOP( "Forces the game to output graphics at any aspect ratio by expanding the view frustum " "without stretching the image.
This is a hack, and its results will vary widely game " "to game (it often causes the UI to stretch).
" "Game-specific AR/Gecko-code aspect ratio patches are preferable over this if available." "

If unsure, leave this unchecked."); static const char TR_REMOVE_FOG_DESCRIPTION[] = QT_TR_NOOP("Makes distant objects more visible by removing fog, thus increasing the overall " "detail.

Disabling fog will break some games which rely on proper fog " "emulation.

If unsure, leave this " "unchecked."); static const char TR_3D_MODE_DESCRIPTION[] = QT_TR_NOOP( "Selects the stereoscopic 3D mode. Stereoscopy allows a better feeling " "of depth if the necessary hardware is present. Heavily decreases " "emulation speed and sometimes causes issues.

Side-by-Side and Top-and-Bottom are " "used by most 3D TVs.
Anaglyph is used for Red-Cyan colored glasses.
HDMI 3D is " "used when the monitor supports 3D display resolutions.
Passive is another type of 3D " "used by some TVs.

If unsure, select Off."); static const char TR_3D_DEPTH_DESCRIPTION[] = QT_TR_NOOP( "Controls the separation distance between the virtual cameras.

A higher " "value creates a stronger feeling of depth while a lower value is more comfortable."); static const char TR_3D_CONVERGENCE_DESCRIPTION[] = QT_TR_NOOP( "Controls the distance of the convergence plane. This is the distance at which " "virtual objects will appear to be in front of the screen.

A higher value creates " "stronger out-of-screen effects while a lower value is more comfortable."); static const char TR_3D_SWAP_EYES_DESCRIPTION[] = QT_TR_NOOP( "Swaps the left and right eye. Most useful in side-by-side stereoscopy " "mode.

If unsure, leave this unchecked."); static const char TR_3D_PER_EYE_RESOLUTION_DESCRIPTION[] = QT_TR_NOOP("Whether each eye gets full or half image resolution when using side-by-side " "or above-and-below 3D." "

If unsure, leave this unchecked."); static const char TR_FORCE_24BIT_DESCRIPTION[] = QT_TR_NOOP( "Forces the game to render the RGB color channels in 24-bit, thereby increasing " "quality by reducing color banding.

Has no impact on performance and causes " "few graphical issues.

If unsure, leave this " "checked."); static const char TR_DISABLE_COPY_FILTER_DESCRIPTION[] = QT_TR_NOOP( "Disables the blending of adjacent rows when copying the EFB. This is known in " "some games as \"deflickering\" or \"smoothing\".

Disabling the filter has no " "effect on performance, but may result in a sharper image. Causes few " "graphical issues.

If unsure, leave this " "checked."); static const char TR_ARBITRARY_MIPMAP_DETECTION_DESCRIPTION[] = QT_TR_NOOP( "Enables detection of arbitrary mipmaps, which some games use for special distance-based " "effects.

May have false positives that result in blurry textures at increased " "internal " "resolution, such as in games that use very low resolution mipmaps. Disabling this can also " "reduce stutter in games that frequently load new textures.

This setting is disabled " "when GPU Texture Decoding is enabled.

If unsure, leave this " "unchecked."); static const char TR_HDR_DESCRIPTION[] = QT_TR_NOOP( "Enables scRGB HDR output (if supported by your graphics backend and monitor)." " Fullscreen might be required." "

This gives post process shaders more room for accuracy, allows \"AutoHDR\" " "post-process shaders to work, and allows to fully display the PAL and NTSC-J color spaces." "

Note that games still render in SDR internally." "

If unsure, leave this unchecked."); m_ir_combo->SetTitle(tr("Internal Resolution")); m_ir_combo->SetDescription(tr(TR_INTERNAL_RESOLUTION_DESCRIPTION)); m_aa_combo->SetTitle(tr("Anti-Aliasing")); m_aa_combo->SetDescription(tr(TR_ANTIALIAS_DESCRIPTION)); m_texture_filtering_combo->SetTitle(tr("Texture Filtering")); m_texture_filtering_combo->SetDescription(tr(TR_FORCE_TEXTURE_FILTERING_DESCRIPTION)); m_output_resampling_combo->SetTitle(tr("Output Resampling")); m_output_resampling_combo->SetDescription(tr(TR_OUTPUT_RESAMPLING_DESCRIPTION)); m_configure_color_correction->SetTitle(tr("Color Correction")); m_configure_color_correction->SetDescription(tr(TR_COLOR_CORRECTION_DESCRIPTION)); m_pp_effect->SetTitle(tr("Post-Processing Effect")); m_pp_effect->SetDescription(tr(TR_POSTPROCESSING_DESCRIPTION)); m_scaled_efb_copy->SetDescription(tr(TR_SCALED_EFB_COPY_DESCRIPTION)); m_per_pixel_lighting->SetDescription(tr(TR_PER_PIXEL_LIGHTING_DESCRIPTION)); m_widescreen_hack->SetDescription(tr(TR_WIDESCREEN_HACK_DESCRIPTION)); m_disable_fog->SetDescription(tr(TR_REMOVE_FOG_DESCRIPTION)); m_force_24bit_color->SetDescription(tr(TR_FORCE_24BIT_DESCRIPTION)); m_disable_copy_filter->SetDescription(tr(TR_DISABLE_COPY_FILTER_DESCRIPTION)); m_arbitrary_mipmap_detection->SetDescription(tr(TR_ARBITRARY_MIPMAP_DETECTION_DESCRIPTION)); m_hdr->SetDescription(tr(TR_HDR_DESCRIPTION)); m_3d_mode->SetTitle(tr("Stereoscopic 3D Mode")); m_3d_mode->SetDescription(tr(TR_3D_MODE_DESCRIPTION)); m_3d_depth->SetTitle(tr("Depth")); m_3d_depth->SetDescription(tr(TR_3D_DEPTH_DESCRIPTION)); m_3d_convergence->SetTitle(tr("Convergence")); m_3d_convergence->SetDescription(tr(TR_3D_CONVERGENCE_DESCRIPTION)); m_3d_per_eye_resolution->SetDescription(tr(TR_3D_PER_EYE_RESOLUTION_DESCRIPTION)); m_3d_swap_eyes->SetDescription(tr(TR_3D_SWAP_EYES_DESCRIPTION)); } void EnhancementsWidget::ConfigureColorCorrection() { ColorCorrectionConfigWindow dialog(this); SetQWidgetWindowDecorations(&dialog); dialog.exec(); } void EnhancementsWidget::ConfigurePostProcessingShader() { const std::string shader = Config::Get(Config::GFX_ENHANCE_POST_SHADER); PostProcessingConfigWindow dialog(this, shader); SetQWidgetWindowDecorations(&dialog); dialog.exec(); }