Move DolphinQt2 to DolphinQt

This commit is contained in:
spycrab
2018-07-07 00:40:15 +02:00
parent 059880bb16
commit 13ba24c5a6
233 changed files with 392 additions and 392 deletions

View File

@ -0,0 +1,222 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt/Config/Graphics/AdvancedWidget.h"
#include <QCheckBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QVBoxLayout>
#include "Core/Config/GraphicsSettings.h"
#include "Core/Config/SYSCONFSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "DolphinQt/Config/Graphics/GraphicsBool.h"
#include "DolphinQt/Config/Graphics/GraphicsChoice.h"
#include "DolphinQt/Config/Graphics/GraphicsWindow.h"
#include "DolphinQt/Settings.h"
#include "VideoCommon/VideoConfig.h"
AdvancedWidget::AdvancedWidget(GraphicsWindow* parent) : GraphicsWidget(parent)
{
CreateWidgets();
LoadSettings();
ConnectWidgets();
AddDescriptions();
connect(parent, &GraphicsWindow::BackendChanged, this, &AdvancedWidget::OnBackendChanged);
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
[=](Core::State state) { OnEmulationStateChanged(state != Core::State::Uninitialized); });
OnBackendChanged();
}
void AdvancedWidget::CreateWidgets()
{
auto* main_layout = new QVBoxLayout;
// Debugging
auto* debugging_box = new QGroupBox(tr("Debugging"));
auto* debugging_layout = new QGridLayout();
debugging_box->setLayout(debugging_layout);
m_enable_wireframe = new GraphicsBool(tr("Enable Wireframe"), Config::GFX_ENABLE_WIREFRAME);
m_show_statistics = new GraphicsBool(tr("Show Statistics"), Config::GFX_OVERLAY_STATS);
m_enable_format_overlay =
new GraphicsBool(tr("Texture Format Overlay"), Config::GFX_TEXFMT_OVERLAY_ENABLE);
m_enable_api_validation =
new GraphicsBool(tr("Enable API Validation Layers"), Config::GFX_ENABLE_VALIDATION_LAYER);
debugging_layout->addWidget(m_enable_wireframe, 0, 0);
debugging_layout->addWidget(m_show_statistics, 0, 1);
debugging_layout->addWidget(m_enable_format_overlay, 1, 0);
debugging_layout->addWidget(m_enable_api_validation, 1, 1);
// Utility
auto* utility_box = new QGroupBox(tr("Utility"));
auto* utility_layout = new QGridLayout();
utility_box->setLayout(utility_layout);
m_dump_textures = new GraphicsBool(tr("Dump Textures"), Config::GFX_DUMP_TEXTURES);
m_load_custom_textures = new GraphicsBool(tr("Load Custom Textures"), Config::GFX_HIRES_TEXTURES);
m_prefetch_custom_textures =
new GraphicsBool(tr("Prefetch Custom Textures"), Config::GFX_CACHE_HIRES_TEXTURES);
m_use_fullres_framedumps = new GraphicsBool(tr("Internal Resolution Frame Dumps"),
Config::GFX_INTERNAL_RESOLUTION_FRAME_DUMPS);
m_dump_efb_target = new GraphicsBool(tr("Dump EFB Target"), Config::GFX_DUMP_EFB_TARGET);
m_disable_vram_copies =
new GraphicsBool(tr("Disable EFB VRAM Copies"), Config::GFX_HACK_DISABLE_COPY_TO_VRAM);
m_enable_freelook = new GraphicsBool(tr("Free Look"), Config::GFX_FREE_LOOK);
m_dump_use_ffv1 = new GraphicsBool(tr("Frame Dumps Use FFV1"), Config::GFX_USE_FFV1);
utility_layout->addWidget(m_dump_textures, 0, 0);
utility_layout->addWidget(m_load_custom_textures, 0, 1);
utility_layout->addWidget(m_prefetch_custom_textures, 1, 0);
utility_layout->addWidget(m_use_fullres_framedumps, 1, 1);
utility_layout->addWidget(m_dump_efb_target, 2, 0);
utility_layout->addWidget(m_disable_vram_copies, 2, 1);
utility_layout->addWidget(m_enable_freelook, 3, 0);
#if defined(HAVE_FFMPEG)
utility_layout->addWidget(m_dump_use_ffv1, 3, 1);
#endif
// Misc.
auto* misc_box = new QGroupBox(tr("Misc"));
auto* misc_layout = new QGridLayout();
misc_box->setLayout(misc_layout);
m_enable_cropping = new GraphicsBool(tr("Crop"), Config::GFX_CROP);
m_enable_prog_scan = new QCheckBox(tr("Enable Progressive Scan"));
misc_layout->addWidget(m_enable_cropping, 0, 0);
misc_layout->addWidget(m_enable_prog_scan, 0, 1);
#ifdef _WIN32
m_borderless_fullscreen =
new GraphicsBool(tr("Borderless Fullscreen"), Config::GFX_BORDERLESS_FULLSCREEN);
misc_layout->addWidget(m_borderless_fullscreen, 1, 0);
#endif
main_layout->addWidget(debugging_box);
main_layout->addWidget(utility_box);
main_layout->addWidget(misc_box);
main_layout->addStretch();
setLayout(main_layout);
}
void AdvancedWidget::ConnectWidgets()
{
connect(m_load_custom_textures, &QCheckBox::toggled, this, &AdvancedWidget::SaveSettings);
connect(m_enable_prog_scan, &QCheckBox::toggled, this, &AdvancedWidget::SaveSettings);
}
void AdvancedWidget::LoadSettings()
{
m_prefetch_custom_textures->setEnabled(Config::Get(Config::GFX_HIRES_TEXTURES));
m_enable_prog_scan->setChecked(Config::Get(Config::SYSCONF_PROGRESSIVE_SCAN));
}
void AdvancedWidget::SaveSettings()
{
const auto hires_enabled = Config::Get(Config::GFX_HIRES_TEXTURES);
m_prefetch_custom_textures->setEnabled(hires_enabled);
Config::SetBase(Config::SYSCONF_PROGRESSIVE_SCAN, m_enable_prog_scan->isChecked());
}
void AdvancedWidget::OnBackendChanged()
{
}
void AdvancedWidget::OnEmulationStateChanged(bool running)
{
m_enable_prog_scan->setEnabled(!running);
}
void AdvancedWidget::AddDescriptions()
{
static const char TR_WIREFRAME_DESCRIPTION[] =
QT_TR_NOOP("Render the scene as a wireframe.\n\nIf unsure, leave this unchecked.");
static const char TR_SHOW_STATS_DESCRIPTION[] =
QT_TR_NOOP("Show various rendering statistics.\n\nIf unsure, leave this unchecked.");
static const char TR_TEXTURE_FORMAT_DECRIPTION[] =
QT_TR_NOOP("Modify textures to show the format they're encoded in. Needs an emulation reset "
"in most cases.\n\nIf unsure, leave this unchecked.");
static const char TR_VALIDATION_LAYER_DESCRIPTION[] =
QT_TR_NOOP("Enables validation of API calls made by the video backend, which may assist in "
"debugging graphical issues.\n\nIf unsure, leave this unchecked.");
static const char TR_DUMP_TEXTURE_DESCRIPTION[] =
QT_TR_NOOP("Dump decoded game textures to User/Dump/Textures/<game_id>/.\n\nIf unsure, leave "
"this unchecked.");
static const char TR_LOAD_CUSTOM_TEXTURE_DESCRIPTION[] = QT_TR_NOOP(
"Load custom textures from User/Load/Textures/<game_id>/.\n\nIf unsure, leave this "
"unchecked.");
static const char TR_CACHE_CUSTOM_TEXTURE_DESCRIPTION[] =
QT_TR_NOOP("Cache custom textures to system RAM on startup.\nThis can require exponentially "
"more RAM but fixes possible stuttering.\n\nIf unsure, leave this unchecked.");
static const char TR_DUMP_EFB_DESCRIPTION[] =
QT_TR_NOOP("Dump the contents of EFB copies to User/Dump/Textures/.\n\nIf unsure, leave this "
"unchecked.");
static const char TR_DISABLE_VRAM_COPIES_DESCRIPTION[] =
QT_TR_NOOP("Disables the VRAM copy of the EFB, forcing a round-trip to RAM. Inhibits all "
"upscaling.\n\nIf unsure, leave this unchecked.");
static const char TR_INTERNAL_RESOLUTION_FRAME_DUMPING_DESCRIPTION[] = QT_TR_NOOP(
"Create frame dumps and screenshots at the internal resolution of the renderer, rather than "
"the size of the window it is displayed within. If the aspect ratio is widescreen, the "
"output "
"image will be scaled horizontally to preserve the vertical resolution.\n\nIf unsure, leave "
"this unchecked.");
#if defined(HAVE_FFMPEG)
static const char TR_USE_FFV1_DESCRIPTION[] =
QT_TR_NOOP("Encode frame dumps using the FFV1 codec.\n\nIf unsure, leave this unchecked.");
#endif
static const char TR_FREE_LOOK_DESCRIPTION[] = QT_TR_NOOP(
"This feature allows you to change the game's camera.\nMove the mouse while holding the "
"right "
"mouse button to pan and while holding the middle button to move.\nHold SHIFT and press "
"one of "
"the WASD keys to move the camera by a certain step distance (SHIFT+2 to move faster and "
"SHIFT+1 to move slower). Press SHIFT+R to reset the camera and SHIFT+F to reset the "
"speed.\n\nIf unsure, leave this unchecked.");
static const char TR_CROPPING_DESCRIPTION[] =
QT_TR_NOOP("Crop the picture from its native aspect ratio to 4:3 or "
"16:9.\n\nIf unsure, leave this unchecked.");
static const char TR_PROGRESSIVE_SCAN_DESCRIPTION[] = QT_TR_NOOP(
"Enables progressive scan if supported by the emulated software.\nMost games don't "
"care about this.\n\nIf unsure, leave this unchecked.");
#ifdef _WIN32
static const char TR_BORDERLESS_FULLSCREEN_DESCRIPTION[] = QT_TR_NOOP(
"Implement fullscreen mode with a borderless window spanning the whole screen instead of "
"using "
"exclusive mode.\nAllows for faster transitions between fullscreen and windowed mode, but "
"slightly increases input latency, makes movement less smooth and slightly decreases "
"performance.\nExclusive mode is required for Nvidia 3D Vision to work in the Direct3D "
"backend.\n\nIf unsure, leave this unchecked.");
#endif
AddDescription(m_enable_wireframe, TR_WIREFRAME_DESCRIPTION);
AddDescription(m_show_statistics, TR_SHOW_STATS_DESCRIPTION);
AddDescription(m_enable_format_overlay, TR_TEXTURE_FORMAT_DECRIPTION);
AddDescription(m_enable_api_validation, TR_VALIDATION_LAYER_DESCRIPTION);
AddDescription(m_dump_textures, TR_DUMP_TEXTURE_DESCRIPTION);
AddDescription(m_load_custom_textures, TR_LOAD_CUSTOM_TEXTURE_DESCRIPTION);
AddDescription(m_prefetch_custom_textures, TR_CACHE_CUSTOM_TEXTURE_DESCRIPTION);
AddDescription(m_dump_efb_target, TR_DUMP_EFB_DESCRIPTION);
AddDescription(m_disable_vram_copies, TR_DISABLE_VRAM_COPIES_DESCRIPTION);
AddDescription(m_use_fullres_framedumps, TR_INTERNAL_RESOLUTION_FRAME_DUMPING_DESCRIPTION);
#ifdef HAVE_FFMPEG
AddDescription(m_dump_use_ffv1, TR_USE_FFV1_DESCRIPTION);
#endif
AddDescription(m_enable_cropping, TR_CROPPING_DESCRIPTION);
AddDescription(m_enable_prog_scan, TR_PROGRESSIVE_SCAN_DESCRIPTION);
AddDescription(m_enable_freelook, TR_FREE_LOOK_DESCRIPTION);
#ifdef _WIN32
AddDescription(m_borderless_fullscreen, TR_BORDERLESS_FULLSCREEN_DESCRIPTION);
#endif
}

View File

@ -0,0 +1,48 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "DolphinQt/Config/Graphics/GraphicsWidget.h"
class GraphicsWindow;
class QCheckBox;
class AdvancedWidget final : public GraphicsWidget
{
Q_OBJECT
public:
explicit AdvancedWidget(GraphicsWindow* parent);
private:
void LoadSettings() override;
void SaveSettings() override;
void CreateWidgets();
void ConnectWidgets();
void AddDescriptions();
void OnBackendChanged();
void OnEmulationStateChanged(bool running);
// Debugging
QCheckBox* m_enable_wireframe;
QCheckBox* m_show_statistics;
QCheckBox* m_enable_format_overlay;
QCheckBox* m_enable_api_validation;
// Utility
QCheckBox* m_dump_textures;
QCheckBox* m_prefetch_custom_textures;
QCheckBox* m_dump_efb_target;
QCheckBox* m_disable_vram_copies;
QCheckBox* m_dump_use_ffv1;
QCheckBox* m_load_custom_textures;
QCheckBox* m_use_fullres_framedumps;
QCheckBox* m_enable_freelook;
// Misc
QCheckBox* m_enable_cropping;
QCheckBox* m_enable_prog_scan;
QCheckBox* m_borderless_fullscreen;
};

View File

@ -0,0 +1,381 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt/Config/Graphics/EnhancementsWidget.h"
#include <cmath>
#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include "Core/Config/GraphicsSettings.h"
#include "Core/ConfigManager.h"
#include "DolphinQt/Config/Graphics/GraphicsBool.h"
#include "DolphinQt/Config/Graphics/GraphicsChoice.h"
#include "DolphinQt/Config/Graphics/GraphicsSlider.h"
#include "DolphinQt/Config/Graphics/GraphicsWindow.h"
#include "DolphinQt/Config/Graphics/PostProcessingConfigWindow.h"
#include "DolphinQt/Settings.h"
#include "UICommon/VideoUtils.h"
#include "VideoCommon/PostProcessing.h"
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoConfig.h"
EnhancementsWidget::EnhancementsWidget(GraphicsWindow* parent)
: GraphicsWidget(parent), m_block_save(false)
{
CreateWidgets();
LoadSettings();
ConnectWidgets();
AddDescriptions();
connect(parent, &GraphicsWindow::BackendChanged,
[this](const QString& backend) { LoadSettings(); });
}
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);
m_ir_combo = new GraphicsChoice({tr("Auto (Multiple of 640x528)"), tr("Native (640x528)"),
tr("2x Native (1280x1056) for 720p"),
tr("3x Native (1920x1584) for 1080p"),
tr("4x Native (2560x2112) for 1440p"),
tr("5x Native (3200x2640)"), tr("6x Native (3840x3168) for 4K"),
tr("7x Native (4480x3696)"), tr("8x Native (5120x4224) for 5K")},
Config::GFX_EFB_SCALE);
if (g_Config.iEFBScale > 8)
{
m_ir_combo->addItem(tr("Custom"));
m_ir_combo->setCurrentIndex(m_ir_combo->count() - 1);
}
m_ir_combo->setMaxVisibleItems(m_ir_combo->count());
m_aa_combo = new QComboBox();
m_af_combo = new GraphicsChoice({tr("1x"), tr("2x"), tr("4x"), tr("8x"), tr("16x")},
Config::GFX_ENHANCE_MAX_ANISOTROPY);
m_pp_effect = new QComboBox();
m_configure_pp_effect = new QPushButton(tr("Configure"));
m_scaled_efb_copy = new GraphicsBool(tr("Scaled EFB Copy"), Config::GFX_HACK_COPY_EFB_SCALED);
m_per_pixel_lighting =
new GraphicsBool(tr("Per-Pixel Lighting"), Config::GFX_ENABLE_PIXEL_LIGHTING);
m_force_texture_filtering =
new GraphicsBool(tr("Force Texture Filtering"), Config::GFX_ENHANCE_FORCE_FILTERING);
m_widescreen_hack = new GraphicsBool(tr("Widescreen Hack"), Config::GFX_WIDESCREEN_HACK);
m_disable_fog = new GraphicsBool(tr("Disable Fog"), Config::GFX_DISABLE_FOG);
m_force_24bit_color =
new GraphicsBool(tr("Force 24-Bit Color"), Config::GFX_ENHANCE_FORCE_TRUE_COLOR);
m_disable_copy_filter =
new GraphicsBool(tr("Disable Copy Filter"), Config::GFX_ENHANCE_DISABLE_COPY_FILTER);
m_arbitrary_mipmap_detection = new GraphicsBool(tr("Arbitrary Mipmap Detection"),
Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION);
enhancements_layout->addWidget(new QLabel(tr("Internal Resolution:")), 0, 0);
enhancements_layout->addWidget(m_ir_combo, 0, 1, 1, -1);
enhancements_layout->addWidget(new QLabel(tr("Anti-Aliasing:")), 1, 0);
enhancements_layout->addWidget(m_aa_combo, 1, 1, 1, -1);
enhancements_layout->addWidget(new QLabel(tr("Anisotropic Filtering:")), 2, 0);
enhancements_layout->addWidget(m_af_combo, 2, 1, 1, -1);
enhancements_layout->addWidget(new QLabel(tr("Post-Processing Effect:")), 4, 0);
enhancements_layout->addWidget(m_pp_effect, 4, 1);
enhancements_layout->addWidget(m_configure_pp_effect, 4, 2);
enhancements_layout->addWidget(m_scaled_efb_copy, 5, 0);
enhancements_layout->addWidget(m_per_pixel_lighting, 5, 1);
enhancements_layout->addWidget(m_force_texture_filtering, 6, 0);
enhancements_layout->addWidget(m_widescreen_hack, 6, 1);
enhancements_layout->addWidget(m_disable_fog, 7, 0);
enhancements_layout->addWidget(m_force_24bit_color, 7, 1);
enhancements_layout->addWidget(m_disable_copy_filter, 8, 0);
enhancements_layout->addWidget(m_arbitrary_mipmap_detection, 8, 1);
// Stereoscopy
auto* stereoscopy_box = new QGroupBox(tr("Stereoscopy"));
auto* stereoscopy_layout = new QGridLayout();
stereoscopy_box->setLayout(stereoscopy_layout);
m_3d_mode = new GraphicsChoice(
{tr("Off"), tr("Side-by-Side"), tr("Top-and-Bottom"), tr("Anaglyph"), tr("HDMI 3D")},
Config::GFX_STEREO_MODE);
m_3d_depth = new GraphicsSlider(0, 100, Config::GFX_STEREO_DEPTH);
m_3d_convergence = new GraphicsSlider(0, 200, Config::GFX_STEREO_CONVERGENCE, 100);
m_3d_swap_eyes = new GraphicsBool(tr("Swap Eyes"), Config::GFX_STEREO_SWAP_EYES);
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);
main_layout->addWidget(enhancements_box);
main_layout->addWidget(stereoscopy_box);
main_layout->addStretch();
setLayout(main_layout);
}
void EnhancementsWidget::ConnectWidgets()
{
connect(m_aa_combo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
[this](int) { SaveSettings(); });
connect(m_pp_effect, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
[this](int) { SaveSettings(); });
connect(m_3d_mode, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
[this] {
m_block_save = true;
LoadPPShaders();
m_block_save = false;
SaveSettings();
});
connect(m_configure_pp_effect, &QPushButton::pressed, this,
&EnhancementsWidget::ConfigurePostProcessingShader);
}
void EnhancementsWidget::LoadPPShaders()
{
const bool anaglyph = g_Config.stereo_mode == StereoMode::Anaglyph;
std::vector<std::string> shaders =
g_Config.stereo_mode == StereoMode::Anaglyph ?
PostProcessingShaderImplementation::GetAnaglyphShaderList(
g_Config.backend_info.api_type) :
PostProcessingShaderImplementation::GetShaderList(g_Config.backend_info.api_type);
m_pp_effect->clear();
if (!anaglyph)
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 (anaglyph && !found)
m_pp_effect->setCurrentIndex(m_pp_effect->findText(QStringLiteral("dubois")));
const bool supports_postprocessing = g_Config.backend_info.bSupportsPostProcessing;
m_pp_effect->setEnabled(supports_postprocessing);
m_pp_effect->setToolTip(supports_postprocessing ?
QStringLiteral("") :
tr("%1 doesn't support this feature.")
.arg(tr(g_video_backend->GetDisplayName().c_str())));
PostProcessingShaderConfiguration pp_shader;
if (selected_shader != "(off)" && 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;
// Anti-Aliasing
int aa_selection = Config::Get(Config::GFX_MSAA);
bool ssaa = Config::Get(Config::GFX_SSAA);
m_aa_combo->clear();
for (const auto& option : VideoUtils::GetAvailableAntialiasingModes(m_msaa_modes))
m_aa_combo->addItem(option == "None" ? tr("None") : QString::fromStdString(option));
m_aa_combo->setCurrentText(
QString::fromStdString(std::to_string(aa_selection) + "x " + (ssaa ? "SSAA" : "MSAA")));
m_aa_combo->setEnabled(m_aa_combo->count() > 1);
// Post Processing Shader
LoadPPShaders();
// Stereoscopy
bool supports_stereoscopy = g_Config.backend_info.bSupportsGeometryShaders;
bool supports_3dvision = g_Config.backend_info.bSupports3DVision;
bool has_3dvision = m_3d_mode->count() == 6;
if (has_3dvision && !supports_3dvision)
m_3d_mode->removeItem(5);
if (!has_3dvision && supports_3dvision)
m_3d_mode->addItem(tr("NVIDIA 3D Vision"));
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_block_save = false;
}
void EnhancementsWidget::SaveSettings()
{
if (m_block_save)
return;
bool is_ssaa = m_aa_combo->currentText().endsWith(QStringLiteral("SSAA"));
int aa_value = m_aa_combo->currentIndex();
if (aa_value == 0)
{
aa_value = 1;
}
else
{
if (aa_value > m_msaa_modes)
aa_value -= m_msaa_modes;
aa_value = std::pow(2, aa_value);
}
Config::SetBaseOrCurrent(Config::GFX_MSAA, static_cast<unsigned int>(aa_value));
Config::SetBaseOrCurrent(Config::GFX_SSAA, is_ssaa);
Config::SetBaseOrCurrent(
Config::GFX_ENHANCE_POST_SHADER,
m_pp_effect->currentIndex() == 0 ? "(off)" : m_pp_effect->currentText().toStdString());
PostProcessingShaderConfiguration pp_shader;
if (Config::Get(Config::GFX_ENHANCE_POST_SHADER) != "(off)")
{
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("Specifies the resolution used to render at. 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 is, the "
"better your performance will be.\n\nIf unsure, select Native.");
static const char TR_ANTIALIAS_DESCRIPTION[] =
QT_TR_NOOP("Reduces the amount of aliasing caused by rasterizing 3D graphics. This smooths "
"out jagged edges on objects.\nIncreases 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.\n\nIf unsure, select None.");
static const char TR_ANISOTROPIC_FILTERING_DESCRIPTION[] = QT_TR_NOOP(
"Enable anisotropic filtering.\nEnhances visual quality of textures that are at oblique "
"viewing angles.\nMight cause issues in a small number of games.\n\nIf unsure, select 1x.");
static const char TR_POSTPROCESSING_DESCRIPTION[] = QT_TR_NOOP(
"Apply a post-processing effect after finishing a frame.\n\nIf unsure, select (off).");
static const char TR_SCALED_EFB_COPY_DESCRIPTION[] = QT_TR_NOOP(
"Greatly increases quality of textures generated using render-to-texture "
"effects.\nRaising the "
"internal resolution will improve the effect of this setting.\nSlightly increases GPU "
"load and "
"causes relatively few graphical issues.\n\nIf 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.\nRarely causes "
"slowdowns or graphical issues.\n\nIf unsure, leave this unchecked.");
static const char TR_WIDESCREEN_HACK_DESCRIPTION[] = QT_TR_NOOP(
"Forces the game to output graphics for any aspect ratio.\nUse with \"Aspect Ratio\" set to "
"\"Force 16:9\" to force 4:3-only games to run at 16:9.\nRarely produces good results and "
"often partially breaks graphics and game UIs.\nUnnecessary (and detrimental) if using any "
"AR/Gecko-code widescreen patches.\n\nIf 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.\nDisabling fog will break some games which rely on proper fog "
"emulation.\n\nIf unsure, leave this unchecked.");
static const char TR_3D_MODE_DESCRIPTION[] = QT_TR_NOOP(
"Selects the stereoscopic 3D mode. Stereoscopy allows you to get a better feeling "
"of depth if you have the necessary hardware.\nSide-by-Side and Top-and-Bottom are "
"used by most 3D TVs.\nAnaglyph is used for Red-Cyan colored glasses.\nHDMI 3D is "
"used when your monitor supports 3D display resolutions.\nHeavily decreases "
"emulation speed and sometimes causes issues.\n\nIf unsure, select Off.");
static const char TR_3D_DEPTH_DESCRIPTION[] =
QT_TR_NOOP("Controls the separation distance between the virtual cameras.\nA 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.\nA 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. Mostly useful if you want to view side-by-side "
"cross-eyed.\n\nIf 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.\nIt has no impact on performance and causes "
"few graphical issues.\n\nIf unsure, leave this checked.");
static const char TR_FORCE_TEXTURE_FILTERING_DESCRIPTION[] =
QT_TR_NOOP("Filter all textures, including any that the game explicitly set as "
"unfiltered.\nMay improve quality of certain textures in some games, but will "
"cause issues in others.\n\nIf unsure, leave this unchecked.");
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, and causes few "
"graphical issues.\n\nIf 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.\nDisabling this can also "
"reduce stutter in games that frequently load new textures.\nThis feature is not compatible "
"with GPU Texture Decoding.\n\nIf unsure, leave this checked.");
AddDescription(m_ir_combo, TR_INTERNAL_RESOLUTION_DESCRIPTION);
AddDescription(m_aa_combo, TR_ANTIALIAS_DESCRIPTION);
AddDescription(m_af_combo, TR_ANISOTROPIC_FILTERING_DESCRIPTION);
AddDescription(m_pp_effect, TR_POSTPROCESSING_DESCRIPTION);
AddDescription(m_scaled_efb_copy, TR_SCALED_EFB_COPY_DESCRIPTION);
AddDescription(m_per_pixel_lighting, TR_PER_PIXEL_LIGHTING_DESCRIPTION);
AddDescription(m_widescreen_hack, TR_WIDESCREEN_HACK_DESCRIPTION);
AddDescription(m_disable_fog, TR_REMOVE_FOG_DESCRIPTION);
AddDescription(m_force_24bit_color, TR_FORCE_24BIT_DESCRIPTION);
AddDescription(m_force_texture_filtering, TR_FORCE_TEXTURE_FILTERING_DESCRIPTION);
AddDescription(m_disable_copy_filter, TR_DISABLE_COPY_FILTER_DESCRIPTION);
AddDescription(m_arbitrary_mipmap_detection, TR_ARBITRARY_MIPMAP_DETECTION_DESCRIPTION);
AddDescription(m_3d_mode, TR_3D_MODE_DESCRIPTION);
AddDescription(m_3d_depth, TR_3D_DEPTH_DESCRIPTION);
AddDescription(m_3d_convergence, TR_3D_CONVERGENCE_DESCRIPTION);
AddDescription(m_3d_swap_eyes, TR_3D_SWAP_EYES_DESCRIPTION);
}
void EnhancementsWidget::ConfigurePostProcessingShader()
{
const std::string shader = Config::Get(Config::GFX_ENHANCE_POST_SHADER);
PostProcessingConfigWindow(this, shader).exec();
}

View File

@ -0,0 +1,54 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "DolphinQt/Config/Graphics/GraphicsWidget.h"
class GraphicsWindow;
class QCheckBox;
class QComboBox;
class QPushButton;
class QSlider;
class EnhancementsWidget final : public GraphicsWidget
{
Q_OBJECT
public:
explicit EnhancementsWidget(GraphicsWindow* parent);
private:
void LoadSettings() override;
void SaveSettings() override;
void CreateWidgets();
void ConnectWidgets();
void AddDescriptions();
void ConfigurePostProcessingShader();
void LoadPPShaders();
// Enhancements
QComboBox* m_ir_combo;
QComboBox* m_aa_combo;
QComboBox* m_af_combo;
QComboBox* m_pp_effect;
QPushButton* m_configure_pp_effect;
QCheckBox* m_scaled_efb_copy;
QCheckBox* m_per_pixel_lighting;
QCheckBox* m_force_texture_filtering;
QCheckBox* m_widescreen_hack;
QCheckBox* m_disable_fog;
QCheckBox* m_force_24bit_color;
QCheckBox* m_disable_copy_filter;
QCheckBox* m_arbitrary_mipmap_detection;
// Stereoscopy
QComboBox* m_3d_mode;
QSlider* m_3d_depth;
QSlider* m_3d_convergence;
QCheckBox* m_3d_swap_eyes;
int m_msaa_modes;
bool m_block_save;
};

View File

@ -0,0 +1,322 @@
// Copyright 2017 Dolphin Emulator Project5~5~5~
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt/Config/Graphics/GeneralWidget.h"
#include <QCheckBox>
#include <QComboBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QMessageBox>
#include <QRadioButton>
#include <QVBoxLayout>
#include "Core/Config/GraphicsSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "DolphinQt/Config/Graphics/GraphicsBool.h"
#include "DolphinQt/Config/Graphics/GraphicsChoice.h"
#include "DolphinQt/Config/Graphics/GraphicsRadio.h"
#include "DolphinQt/Config/Graphics/GraphicsWindow.h"
#include "DolphinQt/Settings.h"
#include "UICommon/VideoUtils.h"
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoConfig.h"
GeneralWidget::GeneralWidget(X11Utils::XRRConfiguration* xrr_config, GraphicsWindow* parent)
: GraphicsWidget(parent), m_xrr_config(xrr_config)
{
CreateWidgets();
LoadSettings();
ConnectWidgets();
AddDescriptions();
emit BackendChanged(QString::fromStdString(SConfig::GetInstance().m_strVideoBackend));
connect(parent, &GraphicsWindow::BackendChanged, this, &GeneralWidget::OnBackendChanged);
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
[=](Core::State state) { OnEmulationStateChanged(state != Core::State::Uninitialized); });
}
void GeneralWidget::CreateWidgets()
{
auto* main_layout = new QVBoxLayout;
// Basic Section
auto* m_video_box = new QGroupBox(tr("Basic"));
m_video_layout = new QGridLayout();
m_backend_combo = new QComboBox();
m_aspect_combo =
new GraphicsChoice({tr("Auto"), tr("Force 16:9"), tr("Force 4:3"), tr("Stretch to Window")},
Config::GFX_ASPECT_RATIO);
m_adapter_combo = new QComboBox;
m_enable_vsync = new GraphicsBool(tr("V-Sync"), Config::GFX_VSYNC);
m_enable_fullscreen = new QCheckBox(tr("Use Fullscreen"));
m_video_box->setLayout(m_video_layout);
for (auto& backend : g_available_video_backends)
m_backend_combo->addItem(tr(backend->GetDisplayName().c_str()),
QVariant(QString::fromStdString(backend->GetName())));
m_video_layout->addWidget(new QLabel(tr("Backend:")), 0, 0);
m_video_layout->addWidget(m_backend_combo, 0, 1);
m_video_layout->addWidget(new QLabel(tr("Adapter:")), 1, 0);
m_video_layout->addWidget(m_adapter_combo, 1, 1);
m_video_layout->addWidget(new QLabel(tr("Aspect Ratio:")), 3, 0);
m_video_layout->addWidget(m_aspect_combo, 3, 1);
m_video_layout->addWidget(m_enable_vsync, 4, 0);
m_video_layout->addWidget(m_enable_fullscreen, 4, 1);
// Other
auto* m_options_box = new QGroupBox(tr("Other"));
auto* m_options_layout = new QGridLayout();
m_show_fps = new GraphicsBool(tr("Show FPS"), Config::GFX_SHOW_FPS);
m_show_ping = new GraphicsBool(tr("Show NetPlay Ping"), Config::GFX_SHOW_NETPLAY_PING);
m_log_render_time =
new GraphicsBool(tr("Log Render Time to File"), Config::GFX_LOG_RENDER_TIME_TO_FILE);
m_autoadjust_window_size = new QCheckBox(tr("Auto-Adjust Window Size"));
m_show_messages =
new GraphicsBool(tr("Show NetPlay Messages"), Config::GFX_SHOW_NETPLAY_MESSAGES);
m_render_main_window = new QCheckBox(tr("Render to Main Window"));
m_options_box->setLayout(m_options_layout);
m_options_layout->addWidget(m_show_fps, 0, 0);
m_options_layout->addWidget(m_show_ping, 0, 1);
m_options_layout->addWidget(m_log_render_time, 1, 0);
m_options_layout->addWidget(m_autoadjust_window_size, 1, 1);
m_options_layout->addWidget(m_show_messages, 2, 0);
m_options_layout->addWidget(m_render_main_window, 2, 1);
// Other
auto* shader_compilation_box = new QGroupBox(tr("Shader Compilation"));
auto* shader_compilation_layout = new QGridLayout();
const std::array<const char*, 4> modes = {{
"Synchronous",
"Synchronous (Ubershaders)",
"Asynchronous (Ubershaders)",
"Asynchronous (Skip Drawing)",
}};
for (size_t i = 0; i < modes.size(); i++)
{
m_shader_compilation_mode[i] = new GraphicsRadioInt(
tr(modes[i]), Config::GFX_SHADER_COMPILATION_MODE, static_cast<int>(i));
shader_compilation_layout->addWidget(m_shader_compilation_mode[i], static_cast<int>(i / 2),
static_cast<int>(i % 2));
}
m_wait_for_shaders = new GraphicsBool(tr("Compile Shaders Before Starting"),
Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING);
shader_compilation_layout->addWidget(m_wait_for_shaders);
shader_compilation_box->setLayout(shader_compilation_layout);
main_layout->addWidget(m_video_box);
main_layout->addWidget(m_options_box);
main_layout->addWidget(shader_compilation_box);
main_layout->addStretch();
setLayout(main_layout);
}
void GeneralWidget::ConnectWidgets()
{
// Video Backend
connect(m_backend_combo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &GeneralWidget::SaveSettings);
connect(m_adapter_combo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, [](int index) {
g_Config.iAdapter = index;
Config::SetBaseOrCurrent(Config::GFX_ADAPTER, index);
});
for (QCheckBox* checkbox : {m_enable_fullscreen, m_render_main_window, m_autoadjust_window_size})
connect(checkbox, &QCheckBox::toggled, this, &GeneralWidget::SaveSettings);
}
void GeneralWidget::LoadSettings()
{
// Video Backend
m_backend_combo->setCurrentIndex(m_backend_combo->findData(
QVariant(QString::fromStdString(SConfig::GetInstance().m_strVideoBackend))));
// Enable Fullscreen
m_enable_fullscreen->setChecked(SConfig::GetInstance().bFullscreen);
// Render to Main Window
m_render_main_window->setChecked(SConfig::GetInstance().bRenderToMain);
// Autoadjust window size
m_autoadjust_window_size->setChecked(SConfig::GetInstance().bRenderWindowAutoSize);
}
void GeneralWidget::SaveSettings()
{
// Video Backend
const auto current_backend = m_backend_combo->currentData().toString().toStdString();
if (SConfig::GetInstance().m_strVideoBackend != current_backend)
{
if (current_backend == "Software Renderer")
{
QMessageBox confirm_sw(this);
confirm_sw.setIcon(QMessageBox::Warning);
confirm_sw.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
confirm_sw.setWindowTitle(tr("Confirm backend change"));
confirm_sw.setText(tr("Software rendering is an order of magnitude slower than using the "
"other backends.\nIt's only useful for debugging purposes.\nDo you "
"really want to enable software rendering? If unsure, select 'No'."));
if (confirm_sw.exec() != QMessageBox::Yes)
{
m_backend_combo->setCurrentIndex(m_backend_combo->findData(
QVariant(QString::fromStdString(SConfig::GetInstance().m_strVideoBackend))));
return;
}
}
emit BackendChanged(QString::fromStdString(current_backend));
}
// Enable Fullscreen
SConfig::GetInstance().bFullscreen = m_enable_fullscreen->isChecked();
// Autoadjust window size
SConfig::GetInstance().bRenderWindowAutoSize = m_autoadjust_window_size->isChecked();
// Render To Main
SConfig::GetInstance().bRenderToMain = m_render_main_window->isChecked();
}
void GeneralWidget::OnEmulationStateChanged(bool running)
{
m_backend_combo->setEnabled(!running);
m_render_main_window->setEnabled(!running);
m_adapter_combo->setEnabled(!running);
}
void GeneralWidget::AddDescriptions()
{
// We need QObject::tr
#if defined(_WIN32)
static const char TR_BACKEND_DESCRIPTION[] = QT_TR_NOOP(
"Selects which graphics API to use internally.\n\nThe software renderer is extremely "
"slow and only useful for debugging, so you will want to use either OpenGL, Direct3D, "
"or Vulkan. Different games and different GPUs will behave differently on each "
"backend, so for the best emulation experience it is recommended to try each and "
"select the backend that is least problematic.\n\nIf unsure, select OpenGL.");
#else
static const char TR_BACKEND_DESCRIPTION[] =
QT_TR_NOOP("Selects what graphics API to use internally.\nThe software renderer is extremely "
"slow and only useful for debugging, so unless you have a reason to use it you'll "
"want to select OpenGL here.\n\nIf unsure, select OpenGL.");
#endif
static const char TR_ADAPTER_DESCRIPTION[] =
QT_TR_NOOP("Selects a hardware adapter to use.\n\nIf unsure, use the first one.");
static const char TR_FULLSCREEN_DESCRIPTION[] = QT_TR_NOOP(
"Enable this if you want the whole screen to be used for rendering.\nIf this is disabled, a "
"render window will be created instead.\n\nIf unsure, leave this unchecked.");
static const char TR_AUTOSIZE_DESCRIPTION[] =
QT_TR_NOOP("Automatically adjusts the window size to your internal resolution.\n\nIf unsure, "
"leave this unchecked.");
static const char TR_RENDER_TO_MAINWINDOW_DESCRIPTION[] =
QT_TR_NOOP("Enable this if you want to use the main Dolphin window for rendering rather than "
"a separate render window.\n\nIf unsure, leave this unchecked.");
static const char TR_ASPECT_RATIO_DESCRIPTION[] = QT_TR_NOOP(
"Select what aspect ratio to use when rendering:\nAuto: Use the native aspect "
"ratio\nForce 16:9: Mimic an analog TV with a widescreen aspect ratio.\nForce 4:3: "
"Mimic a standard 4:3 analog TV.\nStretch to Window: Stretch the picture to the "
"window size.\n\nIf unsure, select Auto.");
static const char TR_VSYNC_DESCRIPTION[] =
QT_TR_NOOP("Wait for vertical blanks in order to reduce tearing.\nDecreases performance if "
"emulation speed is below 100%.\n\nIf unsure, leave this unchecked.");
static const char TR_SHOW_FPS_DESCRIPTION[] =
QT_TR_NOOP("Show the number of frames rendered per second as a measure of "
"emulation speed.\n\nIf unsure, leave this unchecked.");
static const char TR_SHOW_NETPLAY_PING_DESCRIPTION[] =
QT_TR_NOOP("Show the players' maximum Ping while playing on "
"NetPlay.\n\nIf unsure, leave this unchecked.");
static const char TR_LOG_RENDERTIME_DESCRIPTION[] =
QT_TR_NOOP("Log the render time of every frame to User/Logs/render_time.txt. Use this "
"feature when you want to measure the performance of Dolphin.\n\nIf "
"unsure, leave this unchecked.");
static const char TR_SHOW_NETPLAY_MESSAGES_DESCRIPTION[] =
QT_TR_NOOP("When playing on NetPlay, show chat messages, buffer changes and "
"desync alerts.\n\nIf unsure, leave this unchecked.");
static const char TR_SHADER_COMPILE_SYNC_DESCRIPTION[] =
QT_TR_NOOP("Ubershaders are never used. Stuttering will occur during shader "
"compilation, but GPU demands are low. Recommended for low-end hardware.\n\nIf "
"unsure, select this mode.");
static const char TR_SHADER_COMPILE_UBER_ONLY_DESCRIPTION[] = QT_TR_NOOP(
"Ubershaders will always be used. Provides a near stutter-free experience at the cost of "
"high GPU performance requirements. Only recommended for high-end systems.");
static const char TR_SHADER_COMPILE_ASYNC_UBER_DESCRIPTION[] =
QT_TR_NOOP("Ubershaders will be used to prevent stuttering during shader compilation, but "
"specialized shaders will be used when they will not cause stuttering. In the "
"best case it eliminates shader compilation stuttering while having minimal "
"performance impact, but results depend on video driver behavior.");
static const char TR_SHADER_COMPILE_ASYNC_SKIP_DESCRIPTION[] = QT_TR_NOOP(
"Prevents shader compilation stuttering by not rendering waiting objects. Can work in "
"scenarios where Ubershaders doesn't, at the cost of introducing visual glitches and broken "
"effects. Not recommended, only use if the other options give poor results on your system.");
static const char TR_SHADER_COMPILE_BEFORE_START_DESCRIPTION[] =
QT_TR_NOOP("Waits for all shaders to finish compiling before starting a game. Enabling this "
"option may reduce stuttering or hitching for a short time after the game is "
"started, at the cost of a longer delay before the game starts. For systems with "
"two or fewer cores, it is recommended to enable this option, as a large shader "
"queue may reduce frame rates. Otherwise, if unsure, leave this unchecked.");
AddDescription(m_backend_combo, TR_BACKEND_DESCRIPTION);
AddDescription(m_adapter_combo, TR_ADAPTER_DESCRIPTION);
AddDescription(m_aspect_combo, TR_ASPECT_RATIO_DESCRIPTION);
AddDescription(m_enable_vsync, TR_VSYNC_DESCRIPTION);
AddDescription(m_enable_fullscreen, TR_FULLSCREEN_DESCRIPTION);
AddDescription(m_show_fps, TR_SHOW_FPS_DESCRIPTION);
AddDescription(m_show_ping, TR_SHOW_NETPLAY_PING_DESCRIPTION);
AddDescription(m_log_render_time, TR_LOG_RENDERTIME_DESCRIPTION);
AddDescription(m_autoadjust_window_size, TR_AUTOSIZE_DESCRIPTION);
AddDescription(m_show_messages, TR_SHOW_NETPLAY_MESSAGES_DESCRIPTION);
AddDescription(m_render_main_window, TR_RENDER_TO_MAINWINDOW_DESCRIPTION);
AddDescription(m_shader_compilation_mode[0], TR_SHADER_COMPILE_SYNC_DESCRIPTION);
AddDescription(m_shader_compilation_mode[1], TR_SHADER_COMPILE_UBER_ONLY_DESCRIPTION);
AddDescription(m_shader_compilation_mode[2], TR_SHADER_COMPILE_ASYNC_UBER_DESCRIPTION);
AddDescription(m_shader_compilation_mode[3], TR_SHADER_COMPILE_ASYNC_SKIP_DESCRIPTION);
AddDescription(m_wait_for_shaders, TR_SHADER_COMPILE_BEFORE_START_DESCRIPTION);
}
void GeneralWidget::OnBackendChanged(const QString& backend_name)
{
m_backend_combo->setCurrentIndex(m_backend_combo->findData(QVariant(backend_name)));
const bool old = m_adapter_combo->blockSignals(true);
m_adapter_combo->clear();
const auto& adapters = g_Config.backend_info.Adapters;
for (const auto& adapter : adapters)
m_adapter_combo->addItem(QString::fromStdString(adapter));
const bool supports_adapters = !adapters.empty();
m_adapter_combo->setCurrentIndex(g_Config.iAdapter);
m_adapter_combo->setEnabled(supports_adapters);
m_adapter_combo->setToolTip(supports_adapters ?
QStringLiteral("") :
tr("%1 doesn't support this feature.")
.arg(tr(g_video_backend->GetDisplayName().c_str())));
m_adapter_combo->blockSignals(old);
}

View File

@ -0,0 +1,59 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <array>
#include "DolphinQt/Config/Graphics/GraphicsWidget.h"
class GraphicsWindow;
class QCheckBox;
class QComboBox;
class QRadioButton;
class QGridLayout;
namespace X11Utils
{
class XRRConfiguration;
}
class GeneralWidget final : public GraphicsWidget
{
Q_OBJECT
public:
explicit GeneralWidget(X11Utils::XRRConfiguration* xrr_config, GraphicsWindow* parent);
signals:
void BackendChanged(const QString& backend);
private:
void LoadSettings() override;
void SaveSettings() override;
void CreateWidgets();
void ConnectWidgets();
void AddDescriptions();
void OnBackendChanged(const QString& backend_name);
void OnEmulationStateChanged(bool running);
// Video
QGridLayout* m_video_layout;
QComboBox* m_backend_combo;
QComboBox* m_adapter_combo;
QComboBox* m_aspect_combo;
QCheckBox* m_enable_vsync;
QCheckBox* m_enable_fullscreen;
// Options
QCheckBox* m_show_fps;
QCheckBox* m_show_ping;
QCheckBox* m_log_render_time;
QCheckBox* m_autoadjust_window_size;
QCheckBox* m_show_messages;
QCheckBox* m_render_main_window;
std::array<QRadioButton*, 4> m_shader_compilation_mode{};
QCheckBox* m_wait_for_shaders;
X11Utils::XRRConfiguration* m_xrr_config;
};

View File

@ -0,0 +1,54 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt/Config/Graphics/GraphicsBool.h"
#include "Common/Config/Config.h"
#include "DolphinQt/Settings.h"
#include <QFont>
GraphicsBool::GraphicsBool(const QString& label, const Config::ConfigInfo<bool>& setting,
bool reverse)
: QCheckBox(label), m_setting(setting), m_reverse(reverse)
{
connect(this, &QCheckBox::toggled, this, &GraphicsBool::Update);
setChecked(Config::Get(m_setting) ^ reverse);
connect(&Settings::Instance(), &Settings::ConfigChanged, [this] {
QFont bf = font();
bf.setBold(Config::GetActiveLayerForConfig(m_setting) != Config::LayerType::Base);
setFont(bf);
bool old = blockSignals(true);
setChecked(Config::Get(m_setting) ^ m_reverse);
blockSignals(old);
});
}
void GraphicsBool::Update()
{
Config::SetBaseOrCurrent(m_setting, static_cast<bool>(isChecked() ^ m_reverse));
}
GraphicsBoolEx::GraphicsBoolEx(const QString& label, const Config::ConfigInfo<bool>& setting,
bool reverse)
: QRadioButton(label), m_setting(setting), m_reverse(reverse)
{
connect(this, &QCheckBox::toggled, this, &GraphicsBoolEx::Update);
setChecked(Config::Get(m_setting) ^ reverse);
if (Config::GetActiveLayerForConfig(m_setting) != Config::LayerType::Base)
{
QFont bf = font();
bf.setBold(true);
setFont(bf);
}
}
void GraphicsBoolEx::Update()
{
Config::SetBaseOrCurrent(m_setting, static_cast<bool>(isChecked() ^ m_reverse));
}

View File

@ -0,0 +1,41 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QCheckBox>
#include <QRadioButton>
namespace Config
{
template <typename T>
struct ConfigInfo;
}
class GraphicsBool : public QCheckBox
{
Q_OBJECT
public:
GraphicsBool(const QString& label, const Config::ConfigInfo<bool>& setting, bool reverse = false);
private:
void Update();
const Config::ConfigInfo<bool>& m_setting;
bool m_reverse;
};
class GraphicsBoolEx : public QRadioButton
{
Q_OBJECT
public:
GraphicsBoolEx(const QString& label, const Config::ConfigInfo<bool>& setting,
bool reverse = false);
private:
void Update();
const Config::ConfigInfo<bool>& m_setting;
bool m_reverse;
};

View File

@ -0,0 +1,33 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt/Config/Graphics/GraphicsChoice.h"
#include "Common/Config/Config.h"
#include "DolphinQt/Settings.h"
GraphicsChoice::GraphicsChoice(const QStringList& options, const Config::ConfigInfo<int>& setting)
: m_setting(setting)
{
addItems(options);
connect(this, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
&GraphicsChoice::Update);
setCurrentIndex(Config::Get(m_setting));
connect(&Settings::Instance(), &Settings::ConfigChanged, [this] {
QFont bf = font();
bf.setBold(Config::GetActiveLayerForConfig(m_setting) != Config::LayerType::Base);
setFont(bf);
bool old = blockSignals(true);
setCurrentIndex(Config::Get(m_setting));
blockSignals(old);
});
}
void GraphicsChoice::Update(int choice)
{
Config::SetBaseOrCurrent(m_setting, choice);
}

View File

@ -0,0 +1,21 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QComboBox>
#include "Common/Config/Config.h"
class GraphicsChoice : public QComboBox
{
Q_OBJECT
public:
GraphicsChoice(const QStringList& options, const Config::ConfigInfo<int>& setting);
private:
void Update(int choice);
Config::ConfigInfo<int> m_setting;
};

View File

@ -0,0 +1,35 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt/Config/Graphics/GraphicsRadio.h"
#include "Common/Config/Config.h"
#include "DolphinQt/Settings.h"
GraphicsRadioInt::GraphicsRadioInt(const QString& label, const Config::ConfigInfo<int>& setting,
int value)
: QRadioButton(label), m_setting(setting), m_value(value)
{
setChecked(Config::Get(m_setting) == m_value);
connect(this, &QRadioButton::toggled, this, &GraphicsRadioInt::Update);
connect(&Settings::Instance(), &Settings::ConfigChanged, [this] {
QFont bf = font();
bf.setBold(Config::GetActiveLayerForConfig(m_setting) != Config::LayerType::Base);
setFont(bf);
bool old = blockSignals(true);
setChecked(Config::Get(m_setting) == m_value);
blockSignals(old);
});
}
void GraphicsRadioInt::Update()
{
if (!isChecked())
return;
Config::SetBaseOrCurrent(m_setting, m_value);
}

View File

@ -0,0 +1,22 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QRadioButton>
#include "Common/Config/Config.h"
class GraphicsRadioInt : public QRadioButton
{
Q_OBJECT
public:
GraphicsRadioInt(const QString& label, const Config::ConfigInfo<int>& setting, int value);
private:
void Update();
Config::ConfigInfo<int> m_setting;
int m_value;
};

View File

@ -0,0 +1,37 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt/Config/Graphics/GraphicsSlider.h"
#include "Common/Config/Config.h"
#include "DolphinQt/Settings.h"
GraphicsSlider::GraphicsSlider(int minimum, int maximum, const Config::ConfigInfo<int>& setting,
int tick)
: QSlider(Qt::Horizontal), m_setting(setting)
{
setMinimum(minimum);
setMaximum(maximum);
setTickInterval(tick);
setValue(Config::Get(setting));
connect(this, &GraphicsSlider::valueChanged, this, &GraphicsSlider::Update);
connect(&Settings::Instance(), &Settings::ConfigChanged, [this] {
QFont bf = font();
bf.setBold(Config::GetActiveLayerForConfig(m_setting) != Config::LayerType::Base);
setFont(bf);
bool old = blockSignals(true);
setValue(Config::Get(m_setting));
blockSignals(old);
});
}
void GraphicsSlider::Update(int value)
{
Config::SetBaseOrCurrent(m_setting, value);
}

View File

@ -0,0 +1,24 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QSlider>
namespace Config
{
template <typename T>
struct ConfigInfo;
}
class GraphicsSlider : public QSlider
{
Q_OBJECT
public:
GraphicsSlider(int minimum, int maximum, const Config::ConfigInfo<int>& setting, int tick = 0);
void Update(int value);
private:
const Config::ConfigInfo<int>& m_setting;
};

View File

@ -0,0 +1,20 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt/Config/Graphics/GraphicsWidget.h"
#include <QEvent>
#include <QLabel>
#include "DolphinQt/Config/Graphics/GraphicsWindow.h"
GraphicsWidget::GraphicsWidget(GraphicsWindow* parent)
{
parent->RegisterWidget(this);
}
void GraphicsWidget::AddDescription(QWidget* widget, const char* description)
{
emit DescriptionAdded(widget, description);
}

View File

@ -0,0 +1,31 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QWidget>
class GraphicsWindow;
class QFormLayout;
class QGroupBox;
class QLabel;
class GraphicsWidget : public QWidget
{
Q_OBJECT
public:
explicit GraphicsWidget(GraphicsWindow* parent);
signals:
void DescriptionAdded(QWidget* widget, const char* description);
protected:
void AddDescription(QWidget* widget, const char* description);
virtual void LoadSettings() = 0;
virtual void SaveSettings() = 0;
private:
QFormLayout* m_main_layout;
};

View File

@ -0,0 +1,174 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt/Config/Graphics/GraphicsWindow.h"
#include <QDialogButtonBox>
#include <QEvent>
#include <QGroupBox>
#include <QLabel>
#include <QTabWidget>
#include <QVBoxLayout>
#include "Core/ConfigManager.h"
#include "DolphinQt/Config/Graphics/AdvancedWidget.h"
#include "DolphinQt/Config/Graphics/EnhancementsWidget.h"
#include "DolphinQt/Config/Graphics/GeneralWidget.h"
#include "DolphinQt/Config/Graphics/HacksWidget.h"
#include "DolphinQt/Config/Graphics/SoftwareRendererWidget.h"
#include "DolphinQt/MainWindow.h"
#include "DolphinQt/QtUtils/WrapInScrollArea.h"
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoConfig.h"
GraphicsWindow::GraphicsWindow(X11Utils::XRRConfiguration* xrr_config, MainWindow* parent)
: QDialog(parent), m_xrr_config(xrr_config)
{
// GraphicsWindow initialization is heavy due to dependencies on the graphics subsystem.
// To prevent blocking startup, we create the layout and children at first show time.
}
void GraphicsWindow::Initialize()
{
if (m_lazy_initialized)
return;
m_lazy_initialized = true;
g_Config.Refresh();
g_video_backend->InitBackendInfo();
CreateMainLayout();
setWindowTitle(tr("Graphics"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
OnBackendChanged(QString::fromStdString(SConfig::GetInstance().m_strVideoBackend));
}
void GraphicsWindow::CreateMainLayout()
{
auto* main_layout = new QVBoxLayout();
auto* description_box = new QGroupBox(tr("Description"));
auto* description_layout = new QVBoxLayout();
m_description =
new QLabel(tr("Move the mouse pointer over an option to display a detailed description."));
m_tab_widget = new QTabWidget();
m_button_box = new QDialogButtonBox(QDialogButtonBox::Close);
connect(m_button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
description_box->setLayout(description_layout);
description_box->setFixedHeight(200);
m_description->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_description->setWordWrap(true);
m_description->setAlignment(Qt::AlignTop | Qt::AlignLeft);
description_layout->addWidget(m_description);
main_layout->addWidget(m_tab_widget);
main_layout->addWidget(description_box);
main_layout->addWidget(m_button_box);
m_general_widget = new GeneralWidget(m_xrr_config, this);
m_enhancements_widget = new EnhancementsWidget(this);
m_hacks_widget = new HacksWidget(this);
m_advanced_widget = new AdvancedWidget(this);
m_software_renderer = new SoftwareRendererWidget(this);
connect(m_general_widget, &GeneralWidget::BackendChanged, this,
&GraphicsWindow::OnBackendChanged);
connect(m_software_renderer, &SoftwareRendererWidget::BackendChanged, this,
&GraphicsWindow::OnBackendChanged);
m_wrapped_general = GetWrappedWidget(m_general_widget, this, 50, 305);
m_wrapped_enhancements = GetWrappedWidget(m_enhancements_widget, this, 50, 305);
m_wrapped_hacks = GetWrappedWidget(m_hacks_widget, this, 50, 305);
m_wrapped_advanced = GetWrappedWidget(m_advanced_widget, this, 50, 305);
m_wrapped_software = GetWrappedWidget(m_software_renderer, this, 50, 305);
if (SConfig::GetInstance().m_strVideoBackend != "Software Renderer")
{
m_tab_widget->addTab(m_wrapped_general, tr("General"));
m_tab_widget->addTab(m_wrapped_enhancements, tr("Enhancements"));
m_tab_widget->addTab(m_wrapped_hacks, tr("Hacks"));
m_tab_widget->addTab(m_wrapped_advanced, tr("Advanced"));
}
else
{
m_tab_widget->addTab(m_wrapped_software, tr("Software Renderer"));
}
setLayout(main_layout);
}
void GraphicsWindow::OnBackendChanged(const QString& backend_name)
{
SConfig::GetInstance().m_strVideoBackend = backend_name.toStdString();
for (const auto& backend : g_available_video_backends)
{
if (backend->GetName() == backend_name.toStdString())
{
g_Config.Refresh();
g_video_backend = backend.get();
g_video_backend->InitBackendInfo();
break;
}
}
setWindowTitle(
tr("%1 Graphics Configuration").arg(tr(g_video_backend->GetDisplayName().c_str())));
if (backend_name == QStringLiteral("Software Renderer") && m_tab_widget->count() > 1)
{
m_tab_widget->clear();
m_tab_widget->addTab(m_wrapped_software, tr("Software Renderer"));
}
if (backend_name != QStringLiteral("Software Renderer") && m_tab_widget->count() == 1)
{
m_tab_widget->clear();
m_tab_widget->addTab(m_wrapped_general, tr("General"));
m_tab_widget->addTab(m_wrapped_enhancements, tr("Enhancements"));
m_tab_widget->addTab(m_wrapped_hacks, tr("Hacks"));
m_tab_widget->addTab(m_wrapped_advanced, tr("Advanced"));
}
emit BackendChanged(backend_name);
}
void GraphicsWindow::RegisterWidget(GraphicsWidget* widget)
{
connect(widget, &GraphicsWidget::DescriptionAdded, this, &GraphicsWindow::OnDescriptionAdded);
}
void GraphicsWindow::OnDescriptionAdded(QWidget* widget, const char* description)
{
m_widget_descriptions[widget] = description;
widget->installEventFilter(this);
}
bool GraphicsWindow::eventFilter(QObject* object, QEvent* event)
{
if (!m_widget_descriptions.contains(object))
return false;
if (event->type() == QEvent::Enter)
{
m_description->setText(tr(m_widget_descriptions[object]));
return false;
}
if (event->type() == QEvent::Leave)
{
m_description->setText(
tr("Move the mouse pointer over an option to display a detailed description."));
}
return false;
}

View File

@ -0,0 +1,65 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QDialog>
#include <QHash>
class AdvancedWidget;
class EnhancementsWidget;
class HacksWidget;
class GeneralWidget;
class GraphicsWidget;
class MainWindow;
class QLabel;
class QTabWidget;
class QDialogButtonBox;
class SoftwareRendererWidget;
namespace X11Utils
{
class XRRConfiguration;
}
class GraphicsWindow final : public QDialog
{
Q_OBJECT
public:
explicit GraphicsWindow(X11Utils::XRRConfiguration* xrr_config, MainWindow* parent);
void Initialize();
void RegisterWidget(GraphicsWidget* widget);
bool eventFilter(QObject* object, QEvent* event) override;
signals:
void BackendChanged(const QString& backend);
private:
void CreateMainLayout();
void OnBackendChanged(const QString& backend);
void OnDescriptionAdded(QWidget* widget, const char* description);
bool m_lazy_initialized = false;
QTabWidget* m_tab_widget;
QLabel* m_description;
QDialogButtonBox* m_button_box;
AdvancedWidget* m_advanced_widget;
EnhancementsWidget* m_enhancements_widget;
HacksWidget* m_hacks_widget;
GeneralWidget* m_general_widget;
SoftwareRendererWidget* m_software_renderer;
QWidget* m_wrapped_advanced;
QWidget* m_wrapped_enhancements;
QWidget* m_wrapped_hacks;
QWidget* m_wrapped_general;
QWidget* m_wrapped_software;
X11Utils::XRRConfiguration* m_xrr_config;
QHash<QObject*, const char*> m_widget_descriptions;
};

View File

@ -0,0 +1,251 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt/Config/Graphics/HacksWidget.h"
#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QVBoxLayout>
#include "Core/Config/GraphicsSettings.h"
#include "Core/ConfigManager.h"
#include "DolphinQt/Config/Graphics/GraphicsBool.h"
#include "DolphinQt/Config/Graphics/GraphicsSlider.h"
#include "DolphinQt/Config/Graphics/GraphicsWindow.h"
#include "DolphinQt/Settings.h"
#include "VideoCommon/VideoConfig.h"
HacksWidget::HacksWidget(GraphicsWindow* parent) : GraphicsWidget(parent)
{
CreateWidgets();
LoadSettings();
ConnectWidgets();
AddDescriptions();
connect(parent, &GraphicsWindow::BackendChanged, this, &HacksWidget::OnBackendChanged);
OnBackendChanged(QString::fromStdString(SConfig::GetInstance().m_strVideoBackend));
connect(&Settings::Instance(), &Settings::ConfigChanged, this, &HacksWidget::LoadSettings);
}
void HacksWidget::CreateWidgets()
{
auto* main_layout = new QVBoxLayout;
// EFB
auto* efb_box = new QGroupBox(tr("Embedded Frame Buffer (EFB)"));
auto* efb_layout = new QGridLayout();
efb_box->setLayout(efb_layout);
m_skip_efb_cpu =
new GraphicsBool(tr("Skip EFB Access from CPU"), Config::GFX_HACK_EFB_ACCESS_ENABLE, true);
m_ignore_format_changes = new GraphicsBool(tr("Ignore Format Changes"),
Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES, true);
m_store_efb_copies = new GraphicsBool(tr("Store EFB Copies to Texture Only"),
Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM);
efb_layout->addWidget(m_skip_efb_cpu, 0, 0);
efb_layout->addWidget(m_ignore_format_changes, 0, 1);
efb_layout->addWidget(m_store_efb_copies, 1, 0);
// Texture Cache
auto* texture_cache_box = new QGroupBox(tr("Texture Cache"));
auto* texture_cache_layout = new QGridLayout();
texture_cache_box->setLayout(texture_cache_layout);
m_accuracy = new QSlider(Qt::Horizontal);
m_accuracy->setMinimum(0);
m_accuracy->setMaximum(2);
m_accuracy->setPageStep(1);
m_accuracy->setTickPosition(QSlider::TicksBelow);
m_gpu_texture_decoding =
new GraphicsBool(tr("GPU Texture Decoding"), Config::GFX_ENABLE_GPU_TEXTURE_DECODING);
auto* safe_label = new QLabel(tr("Safe"));
safe_label->setAlignment(Qt::AlignRight);
m_accuracy_label = new QLabel(tr("Accuracy:"));
texture_cache_layout->addWidget(m_accuracy_label, 0, 0);
texture_cache_layout->addWidget(safe_label, 0, 1);
texture_cache_layout->addWidget(m_accuracy, 0, 2);
texture_cache_layout->addWidget(new QLabel(tr("Fast")), 0, 3);
texture_cache_layout->addWidget(m_gpu_texture_decoding, 1, 0);
// XFB
auto* xfb_box = new QGroupBox(tr("External Frame Buffer (XFB)"));
auto* xfb_layout = new QVBoxLayout();
xfb_box->setLayout(xfb_layout);
m_store_xfb_copies = new GraphicsBool(tr("Store XFB Copies to Texture Only"),
Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM);
m_immediate_xfb = new GraphicsBool(tr("Immediately Present XFB"), Config::GFX_HACK_IMMEDIATE_XFB);
xfb_layout->addWidget(m_store_xfb_copies);
xfb_layout->addWidget(m_immediate_xfb);
// Other
auto* other_box = new QGroupBox(tr("Other"));
auto* other_layout = new QGridLayout();
other_box->setLayout(other_layout);
m_fast_depth_calculation =
new GraphicsBool(tr("Fast Depth Calculation"), Config::GFX_FAST_DEPTH_CALC);
m_disable_bounding_box =
new GraphicsBool(tr("Disable Bounding Box"), Config::GFX_HACK_BBOX_ENABLE, true);
m_vertex_rounding = new GraphicsBool(tr("Vertex Rounding"), Config::GFX_HACK_VERTEX_ROUDING);
other_layout->addWidget(m_fast_depth_calculation, 0, 0);
other_layout->addWidget(m_disable_bounding_box, 0, 1);
other_layout->addWidget(m_vertex_rounding, 1, 0);
main_layout->addWidget(efb_box);
main_layout->addWidget(texture_cache_box);
main_layout->addWidget(xfb_box);
main_layout->addWidget(other_box);
main_layout->addStretch();
setLayout(main_layout);
}
void HacksWidget::OnBackendChanged(const QString& backend_name)
{
const bool bbox = g_Config.backend_info.bSupportsBBox;
const bool gpu_texture_decoding = g_Config.backend_info.bSupportsGPUTextureDecoding;
m_gpu_texture_decoding->setEnabled(gpu_texture_decoding);
m_disable_bounding_box->setEnabled(bbox);
if (!gpu_texture_decoding)
m_gpu_texture_decoding->setToolTip(tr("%1 doesn't support this feature.").arg(backend_name));
if (!bbox)
m_disable_bounding_box->setToolTip(tr("%1 doesn't support this feature.").arg(backend_name));
}
void HacksWidget::ConnectWidgets()
{
connect(m_accuracy, &QSlider::valueChanged, [this](int) { SaveSettings(); });
}
void HacksWidget::LoadSettings()
{
const bool old = m_accuracy->blockSignals(true);
auto samples = Config::Get(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES);
int slider_pos = 0;
switch (samples)
{
case 512:
slider_pos = 1;
break;
case 128:
slider_pos = 2;
break;
case 0:
slider_pos = 0;
break;
// Custom values, ought not to be touched
default:
m_accuracy->setEnabled(false);
}
m_accuracy->setValue(slider_pos);
QFont bf = m_accuracy_label->font();
bf.setBold(Config::GetActiveLayerForConfig(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES) !=
Config::LayerType::Base);
m_accuracy_label->setFont(bf);
m_accuracy->blockSignals(old);
}
void HacksWidget::SaveSettings()
{
int slider_pos = m_accuracy->value();
if (m_accuracy->isEnabled())
{
int samples = 0;
switch (slider_pos)
{
case 0:
samples = 0;
break;
case 1:
samples = 512;
break;
case 2:
samples = 128;
}
Config::SetBaseOrCurrent(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES, samples);
}
}
void HacksWidget::AddDescriptions()
{
static const char TR_SKIP_EFB_CPU_ACCESS_DESCRIPTION[] =
QT_TR_NOOP("Ignore any requests from the CPU to read from or write to the EFB.\nImproves "
"performance in some games, but might disable some gameplay-related features or "
"graphical effects.\n\nIf unsure, leave this unchecked.");
static const char TR_IGNORE_FORMAT_CHANGE_DESCRIPTION[] = QT_TR_NOOP(
"Ignore any changes to the EFB format.\nImproves performance in many games without "
"any negative effect. Causes graphical defects in a small number of other "
"games.\n\nIf unsure, leave this checked.");
static const char TR_STORE_EFB_TO_TEXTURE_DESCRIPTION[] = QT_TR_NOOP(
"Stores EFB Copies exclusively on the GPU, bypassing system memory. Causes graphical defects "
"in a small number of games.\n\nEnabled = EFB Copies to Texture\nDisabled = EFB Copies to "
"RAM "
"(and Texture)\n\nIf unsure, leave this checked.");
static const char TR_ACCUARCY_DESCRIPTION[] = QT_TR_NOOP(
"The \"Safe\" setting eliminates the likelihood of the GPU missing texture updates "
"from RAM.\nLower accuracies cause in-game text to appear garbled in certain "
"games.\n\nIf unsure, use the rightmost value.");
static const char TR_STORE_XFB_TO_TEXTURE_DESCRIPTION[] = QT_TR_NOOP(
"Stores XFB Copies exclusively on the GPU, bypassing system memory. Causes graphical defects "
"in a small number of games that need to readback from memory.\n\nEnabled = XFB Copies to "
"Texture\nDisabled = XFB Copies to RAM "
"(and Texture)\n\nIf unsure, leave this checked.");
static const char TR_IMMEDIATE_XFB_DESCRIPTION[] =
QT_TR_NOOP("Displays the XFB copies as soon as they are created, without waiting for "
"scanout. Can cause graphical defects "
"in some games if the game doesn't expect all XFB copies to be displayed. "
"However, turning this setting on reduces latency."
"\n\nIf unsure, leave this unchecked.");
static const char TR_GPU_DECODING_DESCRIPTION[] =
QT_TR_NOOP("Enables texture decoding using the GPU instead of the CPU. This may result in "
"performance gains in some scenarios, or on systems where the CPU is the "
"bottleneck.\n\nIf unsure, leave this unchecked.");
static const char TR_FAST_DEPTH_CALC_DESCRIPTION[] = QT_TR_NOOP(
"Use a less accurate algorithm to calculate depth values.\nCauses issues in a few "
"games, but can give a decent speedup depending on the game and/or your GPU.\n\nIf "
"unsure, leave this checked.");
static const char TR_DISABLE_BOUNDINGBOX_DESCRIPTION[] =
QT_TR_NOOP("Disable the bounding box emulation.\nThis may improve the GPU performance a lot, "
"but some games will break.\n\nIf unsure, leave this checked.");
static const char TR_VERTEX_ROUNDING_DESCRIPTION[] =
QT_TR_NOOP("Rounds 2D vertices to whole pixels. Fixes graphical problems in some games at "
"higher internal resolutions. This setting has no effect when native internal "
"resolution is used.\n\nIf unsure, leave this unchecked.");
AddDescription(m_skip_efb_cpu, TR_SKIP_EFB_CPU_ACCESS_DESCRIPTION);
AddDescription(m_ignore_format_changes, TR_IGNORE_FORMAT_CHANGE_DESCRIPTION);
AddDescription(m_store_efb_copies, TR_STORE_EFB_TO_TEXTURE_DESCRIPTION);
AddDescription(m_accuracy, TR_ACCUARCY_DESCRIPTION);
AddDescription(m_store_xfb_copies, TR_STORE_XFB_TO_TEXTURE_DESCRIPTION);
AddDescription(m_immediate_xfb, TR_IMMEDIATE_XFB_DESCRIPTION);
AddDescription(m_gpu_texture_decoding, TR_GPU_DECODING_DESCRIPTION);
AddDescription(m_fast_depth_calculation, TR_FAST_DEPTH_CALC_DESCRIPTION);
AddDescription(m_disable_bounding_box, TR_DISABLE_BOUNDINGBOX_DESCRIPTION);
AddDescription(m_vertex_rounding, TR_VERTEX_ROUNDING_DESCRIPTION);
}

View File

@ -0,0 +1,49 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "DolphinQt/Config/Graphics/GraphicsWidget.h"
class GraphicsWindow;
class QCheckBox;
class QLabel;
class QRadioButton;
class QSlider;
class HacksWidget final : public GraphicsWidget
{
Q_OBJECT
public:
explicit HacksWidget(GraphicsWindow* parent);
private:
void LoadSettings() override;
void SaveSettings() override;
void OnBackendChanged(const QString& backend_name);
// EFB
QCheckBox* m_skip_efb_cpu;
QCheckBox* m_ignore_format_changes;
QCheckBox* m_store_efb_copies;
// Texture Cache
QLabel* m_accuracy_label;
QSlider* m_accuracy;
QCheckBox* m_gpu_texture_decoding;
// External Framebuffer
QCheckBox* m_store_xfb_copies;
QCheckBox* m_immediate_xfb;
// Other
QCheckBox* m_fast_depth_calculation;
QCheckBox* m_disable_bounding_box;
QCheckBox* m_vertex_rounding;
void CreateWidgets();
void ConnectWidgets();
void AddDescriptions();
};

View File

@ -0,0 +1,362 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt/Config/Graphics/PostProcessingConfigWindow.h"
#include <cmath>
#include <vector>
#include <QCheckBox>
#include <QDialog>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include <QSlider>
#include <QString>
#include <QTabWidget>
#include <QVBoxLayout>
#include <QWidget>
#include "DolphinQt/Config/Graphics/EnhancementsWidget.h"
#include "VideoCommon/PostProcessing.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/VideoConfig.h"
using ConfigurationOption = PostProcessingShaderConfiguration::ConfigurationOption;
using OptionType = ConfigurationOption::OptionType;
PostProcessingConfigWindow::PostProcessingConfigWindow(EnhancementsWidget* parent,
const std::string& shader)
: QDialog(parent), m_shader(shader)
{
if (g_renderer && g_renderer->GetPostProcessor())
{
m_post_processor = g_renderer->GetPostProcessor()->GetConfig();
}
else
{
m_post_processor = new PostProcessingShaderConfiguration();
m_post_processor->LoadShader(m_shader);
}
setWindowTitle(tr("Post Processing Shader Configuration"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
PopulateGroups();
Create();
ConnectWidgets();
}
PostProcessingConfigWindow::~PostProcessingConfigWindow()
{
m_post_processor->SaveOptionsConfiguration();
if (!(g_renderer && g_renderer->GetPostProcessor()))
{
delete m_post_processor;
}
}
void PostProcessingConfigWindow::PopulateGroups()
{
const PostProcessingShaderConfiguration::ConfigMap& config_map = m_post_processor->GetOptions();
auto config_groups = std::vector<std::unique_ptr<ConfigGroup>>();
for (const auto& it : config_map)
{
auto config_group = std::make_unique<ConfigGroup>(&it.second);
m_config_map[it.first] = config_group.get();
config_groups.push_back(std::move(config_group));
}
for (auto& config_group : config_groups)
{
const std::string& parent_name = config_group->GetParent();
if (parent_name.empty())
{
m_config_groups.emplace_back(std::move(config_group));
}
else
{
m_config_map[parent_name]->AddSubGroup(std::move(config_group));
}
}
}
void PostProcessingConfigWindow::Create()
{
m_tabs = new QTabWidget();
auto* const general = new QWidget(m_tabs);
auto* const general_layout = new QGridLayout(general);
u32 row = 0;
bool add_general_page = false;
for (const auto& it : m_config_groups)
{
if (it->HasSubGroups())
{
auto* const tab = CreateDependentTab(it);
m_tabs->addTab(tab, QString::fromStdString(it->GetGUIName()));
}
else
{
if (!add_general_page)
{
add_general_page = true;
}
row = it->AddWidgets(this, general_layout, row);
}
}
if (add_general_page)
{
m_tabs->insertTab(0, general, tr("General"));
}
m_buttons = new QDialogButtonBox(QDialogButtonBox::Ok);
auto* layout = new QVBoxLayout(this);
layout->addWidget(m_tabs);
layout->addWidget(m_buttons);
}
void PostProcessingConfigWindow::ConnectWidgets()
{
connect(m_buttons, &QDialogButtonBox::accepted, this, &PostProcessingConfigWindow::accept);
}
QWidget*
PostProcessingConfigWindow::CreateDependentTab(const std::unique_ptr<ConfigGroup>& config_group)
{
auto* const tab = new QWidget(m_tabs);
auto* const layout = new QGridLayout(tab);
u32 row = config_group->AddWidgets(this, layout, 0);
for (const auto& child : config_group->GetSubGroups())
{
row = child->AddWidgets(this, layout, row);
}
return tab;
}
void PostProcessingConfigWindow::UpdateBool(ConfigGroup* const config_group, const bool state)
{
m_post_processor->SetOptionb(config_group->GetOptionName(), state);
config_group->EnableSuboptions(state);
}
void PostProcessingConfigWindow::UpdateInteger(ConfigGroup* const config_group, const int value)
{
const ConfigurationOption& config_option =
m_post_processor->GetOption(config_group->GetOptionName());
const size_t vector_size = config_option.m_integer_values.size();
for (size_t i = 0; i < vector_size; ++i)
{
const int current_step = config_group->GetSliderValue(i);
const s32 current_value = config_option.m_integer_step_values[i] * current_step +
config_option.m_integer_min_values[i];
m_post_processor->SetOptioni(config_option.m_option_name, static_cast<int>(i), current_value);
config_group->SetSliderText(i, QString::number(current_value));
}
}
void PostProcessingConfigWindow::UpdateFloat(ConfigGroup* const config_group, const int value)
{
const ConfigurationOption& config_option =
m_post_processor->GetOption(config_group->GetOptionName());
const size_t vector_size = config_option.m_float_values.size();
for (size_t i = 0; i < vector_size; ++i)
{
const int current_step = config_group->GetSliderValue(static_cast<unsigned int>(i));
const float current_value =
config_option.m_float_step_values[i] * current_step + config_option.m_float_min_values[i];
m_post_processor->SetOptionf(config_option.m_option_name, static_cast<int>(i), current_value);
config_group->SetSliderText(i, QString::asprintf("%f", current_value));
}
}
PostProcessingConfigWindow::ConfigGroup::ConfigGroup(const ConfigurationOption* config_option)
: m_config_option(config_option)
{
}
const std::string& PostProcessingConfigWindow::ConfigGroup::GetGUIName() const noexcept
{
return m_config_option->m_gui_name;
}
const std::string& PostProcessingConfigWindow::ConfigGroup::GetParent() const noexcept
{
return m_config_option->m_dependent_option;
}
const std::string& PostProcessingConfigWindow::ConfigGroup::GetOptionName() const noexcept
{
return m_config_option->m_option_name;
}
void PostProcessingConfigWindow::ConfigGroup::AddSubGroup(std::unique_ptr<ConfigGroup>&& subgroup)
{
m_subgroups.emplace_back(std::move(subgroup));
}
bool PostProcessingConfigWindow::ConfigGroup::HasSubGroups() const noexcept
{
return !m_subgroups.empty();
}
const std::vector<std::unique_ptr<PostProcessingConfigWindow::ConfigGroup>>&
PostProcessingConfigWindow::ConfigGroup::GetSubGroups() const noexcept
{
return m_subgroups;
}
u32 PostProcessingConfigWindow::ConfigGroup::AddWidgets(PostProcessingConfigWindow* const parent,
QGridLayout* const grid, const u32 row)
{
auto* const name = new QLabel(QString::fromStdString(m_config_option->m_gui_name));
grid->addWidget(name, row, 0);
switch (m_config_option->m_type)
{
case OptionType::OPTION_BOOL:
return AddBool(parent, grid, row);
case OptionType::OPTION_FLOAT:
return AddFloat(parent, grid, row);
case OptionType::OPTION_INTEGER:
return AddInteger(parent, grid, row);
default:
// obviously shouldn't get here
std::abort();
}
}
u32 PostProcessingConfigWindow::ConfigGroup::AddBool(PostProcessingConfigWindow* const parent,
QGridLayout* const grid, const u32 row)
{
m_checkbox = new QCheckBox();
m_checkbox->setChecked(m_config_option->m_bool_value);
QObject::connect(m_checkbox, &QCheckBox::toggled,
[this, parent](bool checked) { parent->UpdateBool(this, checked); });
grid->addWidget(m_checkbox, row, 2);
return row + 1;
}
u32 PostProcessingConfigWindow::ConfigGroup::AddInteger(PostProcessingConfigWindow* const parent,
QGridLayout* const grid, u32 row)
{
const size_t vector_size = m_config_option->m_integer_values.size();
for (size_t i = 0; i < vector_size; ++i)
{
const int current_value = m_config_option->m_integer_values[i];
const double range =
m_config_option->m_integer_max_values[i] - m_config_option->m_integer_min_values[i];
// "How many steps we have is the range divided by the step interval configured.
// This may not be 100% spot on accurate since developers can have odd stepping intervals
// set.
// Round up so if it is outside our range, then set it to the minimum or maximum"
const int steps =
std::ceil(range / static_cast<double>(m_config_option->m_integer_step_values[i]));
auto* const slider = new QSlider(Qt::Orientation::Horizontal);
slider->setMinimum(0);
slider->setMaximum(steps);
slider->setValue(current_value);
slider->setTickInterval(range / steps);
QObject::connect(slider, &QSlider::valueChanged,
[this, parent](int value) { parent->UpdateInteger(this, value); });
auto* const value_box = new QLineEdit(QString::number(current_value));
value_box->setEnabled(false);
grid->addWidget(slider, row, 1);
grid->addWidget(value_box, row, 2);
m_sliders.push_back(slider);
m_value_boxes.push_back(value_box);
if (vector_size > 1)
{
row++;
}
}
return row + 1;
}
u32 PostProcessingConfigWindow::ConfigGroup::AddFloat(PostProcessingConfigWindow* const parent,
QGridLayout* const grid, u32 row)
{
const size_t vector_size = m_config_option->m_float_values.size();
for (size_t i = 0; i < vector_size; ++i)
{
const int current_value =
m_config_option->m_float_values[i] / m_config_option->m_float_step_values[i];
const float range =
m_config_option->m_float_max_values[i] - m_config_option->m_float_min_values[i];
const int steps = std::ceil(range / m_config_option->m_float_step_values[i]);
auto* const slider = new QSlider(Qt::Orientation::Horizontal);
slider->setMinimum(0);
slider->setMaximum(steps);
slider->setValue(current_value);
slider->setTickInterval(range / steps);
QObject::connect(slider, &QSlider::valueChanged,
[this, parent](int value) { parent->UpdateFloat(this, value); });
auto* const value_box =
new QLineEdit(QString::asprintf("%f", m_config_option->m_float_values[i]));
value_box->setEnabled(false);
grid->addWidget(slider, row, 1);
grid->addWidget(value_box, row, 2);
m_sliders.push_back(slider);
m_value_boxes.push_back(value_box);
if (vector_size > 1)
{
row++;
}
}
return row + 1;
}
void PostProcessingConfigWindow::ConfigGroup::EnableSuboptions(const bool state)
{
for (auto& it : m_subgroups)
{
if (it->m_config_option->m_type == OptionType::OPTION_BOOL)
{
it->m_checkbox->setEnabled(state);
}
else
{
for (auto& slider : it->m_sliders)
{
slider->setEnabled(state);
}
}
it->EnableSuboptions(state);
}
}
int PostProcessingConfigWindow::ConfigGroup::GetSliderValue(size_t index) const
{
return m_sliders[index]->value();
}
void PostProcessingConfigWindow::ConfigGroup::SetSliderText(size_t index, const QString& text)
{
m_value_boxes[index]->setText(text);
}

View File

@ -0,0 +1,78 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <QDialog>
#include "Common/CommonTypes.h"
#include "VideoCommon/PostProcessing.h"
class EnhancementsWidget;
class QCheckBox;
class QDialogButtonBox;
class QGridLayout;
class QLineEdit;
class QSlider;
class QTabWidget;
class QWidget;
class PostProcessingConfigWindow final : public QDialog
{
Q_OBJECT
public:
explicit PostProcessingConfigWindow(EnhancementsWidget* parent, const std::string& shader);
~PostProcessingConfigWindow();
private:
class ConfigGroup final
{
public:
explicit ConfigGroup(
const PostProcessingShaderConfiguration::ConfigurationOption* config_option);
const std::string& GetGUIName() const noexcept;
const std::string& GetParent() const noexcept;
const std::string& GetOptionName() const noexcept;
void AddSubGroup(std::unique_ptr<ConfigGroup>&& subgroup);
bool HasSubGroups() const noexcept;
const std::vector<std::unique_ptr<ConfigGroup>>& GetSubGroups() const noexcept;
u32 AddWidgets(PostProcessingConfigWindow* parent, QGridLayout* grid, u32 row);
void EnableSuboptions(bool state);
int GetSliderValue(size_t index) const;
void SetSliderText(size_t index, const QString& text);
private:
u32 AddBool(PostProcessingConfigWindow* parent, QGridLayout* grid, u32 row);
u32 AddInteger(PostProcessingConfigWindow* parent, QGridLayout* grid, u32 row);
u32 AddFloat(PostProcessingConfigWindow* parent, QGridLayout* grid, u32 row);
QCheckBox* m_checkbox;
std::vector<QSlider*> m_sliders;
std::vector<QLineEdit*> m_value_boxes;
const PostProcessingShaderConfiguration::ConfigurationOption* m_config_option;
std::vector<std::unique_ptr<ConfigGroup>> m_subgroups;
};
void Create();
void ConnectWidgets();
QWidget* CreateDependentTab(const std::unique_ptr<ConfigGroup>& config_group);
void PopulateGroups();
void UpdateBool(ConfigGroup* config_group, bool state);
void UpdateInteger(ConfigGroup* config_group, int value);
void UpdateFloat(ConfigGroup* config_group, int value);
QTabWidget* m_tabs;
QDialogButtonBox* m_buttons;
const std::string& m_shader;
PostProcessingShaderConfiguration* m_post_processor;
std::unordered_map<std::string, ConfigGroup*> m_config_map;
std::vector<std::unique_ptr<ConfigGroup>> m_config_groups;
};

View File

@ -0,0 +1,182 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt/Config/Graphics/SoftwareRendererWidget.h"
#include <QComboBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QSpinBox>
#include <QVBoxLayout>
#include "Core/Config/GraphicsSettings.h"
#include "Core/ConfigManager.h"
#include "DolphinQt/Config/Graphics/GraphicsBool.h"
#include "DolphinQt/Config/Graphics/GraphicsWindow.h"
#include "DolphinQt/Settings.h"
#include "UICommon/VideoUtils.h"
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoConfig.h"
SoftwareRendererWidget::SoftwareRendererWidget(GraphicsWindow* parent) : GraphicsWidget(parent)
{
CreateWidgets();
connect(parent, &GraphicsWindow::BackendChanged, [this] { LoadSettings(); });
LoadSettings();
ConnectWidgets();
AddDescriptions();
}
void SoftwareRendererWidget::CreateWidgets()
{
auto* main_layout = new QVBoxLayout;
auto* rendering_box = new QGroupBox(tr("Rendering"));
auto* rendering_layout = new QGridLayout();
m_backend_combo = new QComboBox();
rendering_box->setLayout(rendering_layout);
rendering_layout->addWidget(new QLabel(tr("Backend:")), 1, 1);
rendering_layout->addWidget(m_backend_combo, 1, 2);
for (const auto& backend : g_available_video_backends)
m_backend_combo->addItem(tr(backend->GetDisplayName().c_str()));
auto* overlay_box = new QGroupBox(tr("Overlay Information"));
auto* overlay_layout = new QGridLayout();
overlay_box->setLayout(overlay_layout);
m_show_statistics = new GraphicsBool(tr("Show Statistics"), Config::GFX_OVERLAY_STATS);
overlay_layout->addWidget(m_show_statistics);
auto* utility_box = new QGroupBox(tr("Utility"));
auto* utility_layout = new QGridLayout();
m_dump_textures = new GraphicsBool(tr("Dump Textures"), Config::GFX_DUMP_TEXTURES);
m_dump_objects = new GraphicsBool(tr("Dump Objects"), Config::GFX_SW_DUMP_OBJECTS);
utility_box->setLayout(utility_layout);
utility_layout->addWidget(m_dump_textures, 1, 1);
utility_layout->addWidget(m_dump_objects, 1, 2);
auto* debug_box = new QGroupBox(tr("Debug Only"));
auto* debug_layout = new QGridLayout();
m_dump_tev_stages = new GraphicsBool(tr("Dump TEV Stages"), Config::GFX_SW_DUMP_TEV_STAGES);
m_dump_tev_fetches =
new GraphicsBool(tr("Dump Texture Fetches"), Config::GFX_SW_DUMP_TEV_TEX_FETCHES);
debug_layout->addWidget(m_dump_tev_stages, 1, 1);
debug_layout->addWidget(m_dump_tev_fetches, 1, 2);
debug_box->setLayout(debug_layout);
#ifdef _DEBUG
utility_layout->addWidget(debug_box, 2, 1, 1, 2);
#endif
auto* object_range_box = new QGroupBox(tr("Drawn Object Range"));
auto* object_range_layout = new QGridLayout();
m_object_range_min = new QSpinBox();
m_object_range_max = new QSpinBox();
for (auto* spin : {m_object_range_min, m_object_range_max})
{
spin->setMinimum(0);
spin->setMaximum(100000);
}
object_range_box->setLayout(object_range_layout);
object_range_layout->addWidget(m_object_range_min, 1, 1);
object_range_layout->addWidget(m_object_range_max, 1, 2);
main_layout->addWidget(rendering_box);
main_layout->addWidget(overlay_box);
main_layout->addWidget(utility_box);
main_layout->addWidget(object_range_box);
main_layout->addStretch();
setLayout(main_layout);
}
void SoftwareRendererWidget::ConnectWidgets()
{
connect(m_backend_combo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
[this](int) { SaveSettings(); });
connect(m_object_range_min, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
[this](int) { SaveSettings(); });
connect(m_object_range_max, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
[this](int) { SaveSettings(); });
}
void SoftwareRendererWidget::LoadSettings()
{
for (const auto& backend : g_available_video_backends)
{
if (backend->GetName() == SConfig::GetInstance().m_strVideoBackend)
m_backend_combo->setCurrentIndex(
m_backend_combo->findText(tr(backend->GetDisplayName().c_str())));
}
m_object_range_min->setValue(Config::Get(Config::GFX_SW_DRAW_START));
m_object_range_max->setValue(Config::Get(Config::GFX_SW_DRAW_END));
}
void SoftwareRendererWidget::SaveSettings()
{
for (const auto& backend : g_available_video_backends)
{
if (tr(backend->GetDisplayName().c_str()) == m_backend_combo->currentText())
{
const auto backend_name = backend->GetName();
if (backend_name != SConfig::GetInstance().m_strVideoBackend)
emit BackendChanged(QString::fromStdString(backend_name));
break;
}
}
Config::SetBaseOrCurrent(Config::GFX_SW_DRAW_START, m_object_range_min->value());
Config::SetBaseOrCurrent(Config::GFX_SW_DRAW_END, m_object_range_max->value());
}
void SoftwareRendererWidget::AddDescriptions()
{
static const char TR_BACKEND_DESCRIPTION[] =
QT_TR_NOOP("Selects what graphics API to use internally.\nThe software renderer is extremely "
"slow and only useful for debugging, so you'll want to use either Direct3D or "
"OpenGL. Different games and different GPUs will behave differently on each "
"backend, so for the best emulation experience it's recommended to try both and "
"choose the one that's less problematic.\n\nIf unsure, select OpenGL.");
static const char TR_SHOW_STATISTICS_DESCRIPTION[] =
QT_TR_NOOP("Show various rendering statistics.\n\nIf unsure, leave this unchecked.");
static const char TR_DUMP_TEXTURES_DESCRIPTION[] =
QT_TR_NOOP("Dump decoded game textures to User/Dump/Textures/<game_id>/.\n\nIf unsure, leave "
"this unchecked.");
static const char TR_DUMP_OBJECTS_DESCRIPTION[] =
QT_TR_NOOP("Dump objects to User/Dump/Objects/.\n\nIf unsure, leave "
"this unchecked.");
static const char TR_DUMP_TEV_STAGES_DESCRIPTION[] =
QT_TR_NOOP("Dump TEV Stages to User/Dump/Objects/.\n\nIf unsure, leave "
"this unchecked.");
static const char TR_DUMP_TEV_FETCHES_DESCRIPTION[] =
QT_TR_NOOP("Dump Texture Fetches to User/Dump/Objects/.\n\nIf unsure, leave "
"this unchecked.");
AddDescription(m_backend_combo, TR_BACKEND_DESCRIPTION);
AddDescription(m_show_statistics, TR_SHOW_STATISTICS_DESCRIPTION);
AddDescription(m_dump_textures, TR_DUMP_TEXTURES_DESCRIPTION);
AddDescription(m_dump_objects, TR_DUMP_OBJECTS_DESCRIPTION);
AddDescription(m_dump_tev_stages, TR_DUMP_TEV_STAGES_DESCRIPTION);
AddDescription(m_dump_tev_fetches, TR_DUMP_TEV_FETCHES_DESCRIPTION);
}

View File

@ -0,0 +1,40 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "DolphinQt/Config/Graphics/GraphicsWidget.h"
class GraphicsWindow;
class QCheckBox;
class QComboBox;
class QSpinBox;
class SoftwareRendererWidget final : public GraphicsWidget
{
Q_OBJECT
public:
explicit SoftwareRendererWidget(GraphicsWindow* parent);
signals:
void BackendChanged(const QString& backend);
private:
void LoadSettings() override;
void SaveSettings() override;
void CreateWidgets();
void ConnectWidgets();
void AddDescriptions();
QComboBox* m_backend_combo;
QCheckBox* m_show_statistics;
QCheckBox* m_dump_textures;
QCheckBox* m_dump_objects;
QCheckBox* m_dump_tev_stages;
QCheckBox* m_dump_tev_fetches;
QSpinBox* m_object_range_min;
QSpinBox* m_object_range_max;
};