Merge branch 'master' into qt-inisettings

This commit is contained in:
Connor McLaughlin 2020-07-21 13:28:18 +10:00 committed by GitHub
commit bddd098a66
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 161 additions and 100 deletions

View file

@ -11,6 +11,7 @@ A "BIOS" ROM image is required to to start the emulator and to play games. You c
## Latest News
- 2020/07/18: Widescreen hack enhancement added.
- 2020/07/04: Vulkan renderer now available in libretro core.
- 2020/07/02: Now available as a libretro core.
- 2020/07/01: Lightgun support with custom crosshairs.

View file

@ -29,6 +29,55 @@ class Bus
friend DMA;
public:
enum : u32
{
RAM_BASE = 0x00000000,
RAM_SIZE = 0x200000,
RAM_MASK = RAM_SIZE - 1,
RAM_MIRROR_END = 0x800000,
EXP1_BASE = 0x1F000000,
EXP1_SIZE = 0x800000,
EXP1_MASK = EXP1_SIZE - 1,
MEMCTRL_BASE = 0x1F801000,
MEMCTRL_SIZE = 0x40,
MEMCTRL_MASK = MEMCTRL_SIZE - 1,
PAD_BASE = 0x1F801040,
PAD_SIZE = 0x10,
PAD_MASK = PAD_SIZE - 1,
SIO_BASE = 0x1F801050,
SIO_SIZE = 0x10,
SIO_MASK = SIO_SIZE - 1,
MEMCTRL2_BASE = 0x1F801060,
MEMCTRL2_SIZE = 0x10,
MEMCTRL2_MASK = MEMCTRL_SIZE - 1,
INTERRUPT_CONTROLLER_BASE = 0x1F801070,
INTERRUPT_CONTROLLER_SIZE = 0x10,
INTERRUPT_CONTROLLER_MASK = INTERRUPT_CONTROLLER_SIZE - 1,
DMA_BASE = 0x1F801080,
DMA_SIZE = 0x80,
DMA_MASK = DMA_SIZE - 1,
TIMERS_BASE = 0x1F801100,
TIMERS_SIZE = 0x40,
TIMERS_MASK = TIMERS_SIZE - 1,
CDROM_BASE = 0x1F801800,
CDROM_SIZE = 0x10,
CDROM_MASK = CDROM_SIZE - 1,
GPU_BASE = 0x1F801810,
GPU_SIZE = 0x10,
GPU_MASK = GPU_SIZE - 1,
MDEC_BASE = 0x1F801820,
MDEC_SIZE = 0x10,
MDEC_MASK = MDEC_SIZE - 1,
SPU_BASE = 0x1F801C00,
SPU_SIZE = 0x400,
SPU_MASK = 0x3FF,
EXP2_BASE = 0x1F802000,
EXP2_SIZE = 0x2000,
EXP2_MASK = EXP2_SIZE - 1,
BIOS_BASE = 0x1FC00000,
BIOS_SIZE = 0x80000
};
Bus();
~Bus();
@ -85,56 +134,10 @@ public:
/// Clears all code bits for RAM regions.
ALWAYS_INLINE void ClearRAMCodePageFlags() { m_ram_code_bits.reset(); }
private:
enum : u32
{
RAM_BASE = 0x00000000,
RAM_SIZE = 0x200000,
RAM_MASK = RAM_SIZE - 1,
RAM_MIRROR_END = 0x800000,
EXP1_BASE = 0x1F000000,
EXP1_SIZE = 0x800000,
EXP1_MASK = EXP1_SIZE - 1,
MEMCTRL_BASE = 0x1F801000,
MEMCTRL_SIZE = 0x40,
MEMCTRL_MASK = MEMCTRL_SIZE - 1,
PAD_BASE = 0x1F801040,
PAD_SIZE = 0x10,
PAD_MASK = PAD_SIZE - 1,
SIO_BASE = 0x1F801050,
SIO_SIZE = 0x10,
SIO_MASK = SIO_SIZE - 1,
MEMCTRL2_BASE = 0x1F801060,
MEMCTRL2_SIZE = 0x10,
MEMCTRL2_MASK = MEMCTRL_SIZE - 1,
INTERRUPT_CONTROLLER_BASE = 0x1F801070,
INTERRUPT_CONTROLLER_SIZE = 0x10,
INTERRUPT_CONTROLLER_MASK = INTERRUPT_CONTROLLER_SIZE - 1,
DMA_BASE = 0x1F801080,
DMA_SIZE = 0x80,
DMA_MASK = DMA_SIZE - 1,
TIMERS_BASE = 0x1F801100,
TIMERS_SIZE = 0x40,
TIMERS_MASK = TIMERS_SIZE - 1,
CDROM_BASE = 0x1F801800,
CDROM_SIZE = 0x10,
CDROM_MASK = CDROM_SIZE - 1,
GPU_BASE = 0x1F801810,
GPU_SIZE = 0x10,
GPU_MASK = GPU_SIZE - 1,
MDEC_BASE = 0x1F801820,
MDEC_SIZE = 0x10,
MDEC_MASK = MDEC_SIZE - 1,
SPU_BASE = 0x1F801C00,
SPU_SIZE = 0x400,
SPU_MASK = 0x3FF,
EXP2_BASE = 0x1F802000,
EXP2_SIZE = 0x2000,
EXP2_MASK = EXP2_SIZE - 1,
BIOS_BASE = 0x1FC00000,
BIOS_SIZE = 0x80000
};
/// Direct access to RAM - used by DMA.
ALWAYS_INLINE u8* GetRAM() { return m_ram; }
private:
enum : u32
{
MEMCTRL_REG_COUNT = 9
@ -238,9 +241,6 @@ private:
void DoInvalidateCodeCache(u32 page_index);
/// Direct access to RAM - used by DMA.
ALWAYS_INLINE u8* GetRAM() { return m_ram; }
/// Returns the number of cycles stolen by DMA RAM access.
ALWAYS_INLINE static TickCount GetDMARAMTickCount(u32 word_count)
{

View file

@ -54,6 +54,9 @@ public:
ALWAYS_INLINE TickCount GetDowncount() const { return m_downcount; }
ALWAYS_INLINE void SetDowncount(TickCount downcount) { m_downcount = downcount; }
ALWAYS_INLINE const GTE::Core& GetCop2() const { return m_cop2; }
ALWAYS_INLINE GTE::Core& GetCop2() { return m_cop2; }
// Sets the PC and flushes the pipeline.
void SetPC(u32 new_pc);

View file

@ -578,7 +578,10 @@ void Core::RTPS(const s16 V[3], u8 shift, bool lm, bool last)
// MAC0=(((H*20000h/SZ3)+1)/2)*IR1+OFX, SX2=MAC0/10000h ;ScrX FIFO -400h..+3FFh
// MAC0=(((H*20000h/SZ3)+1)/2)*IR2+OFY, SY2=MAC0/10000h ;ScrY FIFO -400h..+3FFh
const s64 result = static_cast<s64>(ZeroExtend64(UNRDivide(m_regs.H, m_regs.SZ3)));
const s64 Sx = s64(result) * s64(m_regs.IR1) + s64(m_regs.OFX);
// (4 / 3) / (16 / 9) -> 0.75 -> (3 / 4)
const s64 Sx = m_widescreen_hack ? ((((s64(result) * s64(m_regs.IR1)) * s64(3)) / s64(4)) + s64(m_regs.OFX)) :
(s64(result) * s64(m_regs.IR1) + s64(m_regs.OFX));
const s64 Sy = s64(result) * s64(m_regs.IR2) + s64(m_regs.OFY);
CheckMACOverflow<0>(Sx);
CheckMACOverflow<0>(Sy);

View file

@ -21,6 +21,8 @@ public:
Core();
~Core();
ALWAYS_INLINE void SetWidescreenHack(bool enabled) { m_widescreen_hack = enabled; }
void Initialize();
void Reset();
bool DoState(StateWrapper& sw);
@ -109,6 +111,7 @@ private:
void Execute_GPF(Instruction inst);
Regs m_regs = {};
bool m_widescreen_hack = false;
};
#include "gte.inl"

View file

@ -8,6 +8,7 @@
#include "common/log.h"
#include "common/string_util.h"
#include "controller.h"
#include "cpu_core.h"
#include "dma.h"
#include "gpu.h"
#include "host_display.h"
@ -345,6 +346,7 @@ void HostInterface::SetDefaultSettings(SettingsInterface& si)
si.SetBoolValue("GPU", "TextureFiltering", false);
si.SetBoolValue("GPU", "DisableInterlacing", false);
si.SetBoolValue("GPU", "ForceNTSCTimings", false);
si.SetBoolValue("GPU", "WidescreenHack", false);
si.SetStringValue("Display", "CropMode", Settings::GetDisplayCropModeName(Settings::DEFAULT_DISPLAY_CROP_MODE));
si.SetStringValue("Display", "AspectRatio",
@ -473,6 +475,9 @@ void HostInterface::CheckForSettingsChanges(const Settings& old_settings)
m_system->GetDMA()->SetMaxSliceTicks(m_settings.dma_max_slice_ticks);
m_system->GetDMA()->SetHaltTicks(m_settings.dma_halt_ticks);
if (m_settings.gpu_widescreen_hack != old_settings.gpu_widescreen_hack)
m_system->GetCPU()->GetCop2().SetWidescreenHack(m_settings.gpu_widescreen_hack);
}
bool controllers_updated = false;

View file

@ -98,6 +98,7 @@ void Settings::Load(SettingsInterface& si)
gpu_texture_filtering = si.GetBoolValue("GPU", "TextureFiltering", false);
gpu_disable_interlacing = si.GetBoolValue("GPU", "DisableInterlacing", false);
gpu_force_ntsc_timings = si.GetBoolValue("GPU", "ForceNTSCTimings", false);
gpu_widescreen_hack = si.GetBoolValue("GPU", "WidescreenHack", false);
display_crop_mode =
ParseDisplayCropMode(
@ -200,6 +201,7 @@ void Settings::Save(SettingsInterface& si) const
si.SetBoolValue("GPU", "TextureFiltering", gpu_texture_filtering);
si.SetBoolValue("GPU", "DisableInterlacing", gpu_disable_interlacing);
si.SetBoolValue("GPU", "ForceNTSCTimings", gpu_force_ntsc_timings);
si.SetBoolValue("GPU", "WidescreenHack", gpu_widescreen_hack);
si.SetStringValue("Display", "CropMode", GetDisplayCropModeName(display_crop_mode));
si.SetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(display_aspect_ratio));
@ -437,10 +439,10 @@ const char* Settings::GetDisplayCropModeDisplayName(DisplayCropMode crop_mode)
return s_display_crop_mode_display_names[static_cast<int>(crop_mode)];
}
static std::array<const char*, 6> s_display_aspect_ratio_names =
{{"4:3", "16:9", "8:7", "2:1 (VRAM 1:1)", "1:1", "PAR 1:1"}};
static constexpr std::array<float, 6> s_display_aspect_ratio_values =
{{4.0f / 3.0f, 16.0f / 9.0f, 8.0f / 7.0f, 2.0f / 1.0f, 1.0f, -1.0f}};
static std::array<const char*, 6> s_display_aspect_ratio_names = {
{"4:3", "16:9", "8:7", "2:1 (VRAM 1:1)", "1:1", "PAR 1:1"}};
static constexpr std::array<float, 6> s_display_aspect_ratio_values = {
{4.0f / 3.0f, 16.0f / 9.0f, 8.0f / 7.0f, 2.0f / 1.0f, 1.0f, -1.0f}};
std::optional<DisplayAspectRatio> Settings::ParseDisplayAspectRatio(const char* str)
{

View file

@ -88,6 +88,7 @@ struct Settings
bool gpu_texture_filtering = false;
bool gpu_disable_interlacing = false;
bool gpu_force_ntsc_timings = false;
bool gpu_widescreen_hack = false;
DisplayCropMode display_crop_mode = DisplayCropMode::None;
DisplayAspectRatio display_aspect_ratio = DisplayAspectRatio::R4_3;
bool display_linear_filtering = true;

View file

@ -242,7 +242,8 @@ bool System::Boot(const SystemBootParameters& params)
bool System::InitializeComponents(bool force_software_renderer)
{
if (!CreateGPU(force_software_renderer ? GPURenderer::Software : GetSettings().gpu_renderer))
const Settings& settings = GetSettings();
if (!CreateGPU(force_software_renderer ? GPURenderer::Software : settings.gpu_renderer))
return false;
m_cpu->Initialize(m_bus.get());
@ -261,6 +262,9 @@ bool System::InitializeComponents(bool force_software_renderer)
m_spu->Initialize(this, m_dma.get(), m_interrupt_controller.get());
m_mdec->Initialize(this, m_dma.get());
// load settings
m_cpu->GetCop2().SetWidescreenHack(settings.gpu_widescreen_hack);
UpdateThrottlePeriod();
return true;
}

View file

@ -5,6 +5,7 @@
#include "common/log.h"
#include "common/string_util.h"
#include "core/analog_controller.h"
#include "core/bus.h"
#include "core/digital_controller.h"
#include "core/game_list.h"
#include "core/gpu.h"
@ -299,6 +300,30 @@ bool LibretroHostInterface::retro_unserialize(const void* data, size_t size)
return true;
}
void* LibretroHostInterface::retro_get_memory_data(unsigned id)
{
switch (id)
{
case RETRO_MEMORY_SYSTEM_RAM:
return m_system ? m_system->GetBus()->GetRAM() : nullptr;
default:
return nullptr;
}
}
size_t LibretroHostInterface::retro_get_memory_size(unsigned id)
{
switch (id)
{
case RETRO_MEMORY_SYSTEM_RAM:
return Bus::RAM_SIZE;
default:
return 0;
}
}
bool LibretroHostInterface::AcquireHostDisplay()
{
// start in software mode, switch to hardware later
@ -323,7 +348,7 @@ void LibretroHostInterface::OnSystemDestroyed()
m_using_hardware_renderer = false;
}
static std::array<retro_core_option_definition, 22> s_option_definitions = {{
static std::array<retro_core_option_definition, 23> s_option_definitions = {{
{"Console.Region",
"Console Region",
"Determines which region/hardware to emulate. Auto-Detect will use the region of the disc inserted.",
@ -412,6 +437,12 @@ static std::array<retro_core_option_definition, 22> s_option_definitions = {{
"others will break.",
{{"true", "Enabled"}, {"false", "Disabled"}},
"false"},
{"GPU.WidescreenHack",
"Widescreen Hack",
"Increases the field of view from 4:3 to 16:9 in 3D games. For 2D games, or games which use pre-rendered "
"backgrounds, this enhancement will not work as expected.",
{{"true", "Enabled"}, {"false", "Disabled"}},
"false"},
{"Display.CropMode",
"Crop Mode",
"Changes how much of the image is cropped. Some games display garbage in the overscan area which is typically "

View file

@ -37,6 +37,8 @@ public:
size_t retro_serialize_size();
bool retro_serialize(void* data, size_t size);
bool retro_unserialize(const void* data, size_t size);
void* retro_get_memory_data(unsigned id);
size_t retro_get_memory_size(unsigned id);
protected:
bool AcquireHostDisplay() override;

View file

@ -111,12 +111,12 @@ RETRO_API unsigned retro_get_region(void)
RETRO_API void* retro_get_memory_data(unsigned id)
{
return nullptr;
return g_libretro_host_interface.retro_get_memory_data(id);
}
RETRO_API size_t retro_get_memory_size(unsigned id)
{
return 0;
return g_libretro_host_interface.retro_get_memory_size(id);
}
RETRO_API void retro_set_environment(retro_environment_t f)

View file

@ -214,14 +214,14 @@ GameListSettingsWidget::GameListSettingsWidget(QtHostInterface* host_interface,
m_ui.searchDirectoryList->setCurrentIndex({});
connect(m_ui.searchDirectoryList, &QTableView::clicked, this, &GameListSettingsWidget::onDirectoryListItemClicked);
connect(m_ui.addSearchDirectoryButton, &QToolButton::pressed, this,
&GameListSettingsWidget::onAddSearchDirectoryButtonPressed);
connect(m_ui.removeSearchDirectoryButton, &QToolButton::pressed, this,
&GameListSettingsWidget::onRemoveSearchDirectoryButtonPressed);
connect(m_ui.rescanAllGames, &QToolButton::pressed, this, &GameListSettingsWidget::onRescanAllGamesPressed);
connect(m_ui.scanForNewGames, &QToolButton::pressed, this, &GameListSettingsWidget::onScanForNewGamesPressed);
connect(m_ui.updateRedumpDatabase, &QToolButton::pressed, this,
&GameListSettingsWidget::onUpdateRedumpDatabaseButtonPressed);
connect(m_ui.addSearchDirectoryButton, &QPushButton::clicked, this,
&GameListSettingsWidget::onAddSearchDirectoryButtonClicked);
connect(m_ui.removeSearchDirectoryButton, &QPushButton::clicked, this,
&GameListSettingsWidget::onRemoveSearchDirectoryButtonClicked);
connect(m_ui.rescanAllGames, &QPushButton::clicked, this, &GameListSettingsWidget::onRescanAllGamesClicked);
connect(m_ui.scanForNewGames, &QPushButton::clicked, this, &GameListSettingsWidget::onScanForNewGamesClicked);
connect(m_ui.updateRedumpDatabase, &QPushButton::clicked, this,
&GameListSettingsWidget::onUpdateRedumpDatabaseButtonClicked);
}
GameListSettingsWidget::~GameListSettingsWidget() = default;
@ -248,7 +248,9 @@ void GameListSettingsWidget::onDirectoryListItemClicked(const QModelIndex& index
void GameListSettingsWidget::addSearchDirectory(QWidget* parent_widget)
{
QString dir = QFileDialog::getExistingDirectory(parent_widget, tr("Select Search Directory"));
QString dir =
QDir::toNativeSeparators(QFileDialog::getExistingDirectory(parent_widget, tr("Select Search Directory")));
if (dir.isEmpty())
return;
@ -265,12 +267,12 @@ void GameListSettingsWidget::addSearchDirectory(QWidget* parent_widget)
m_search_directories_model->addEntry(dir, recursive);
}
void GameListSettingsWidget::onAddSearchDirectoryButtonPressed()
void GameListSettingsWidget::onAddSearchDirectoryButtonClicked()
{
addSearchDirectory(this);
}
void GameListSettingsWidget::onRemoveSearchDirectoryButtonPressed()
void GameListSettingsWidget::onRemoveSearchDirectoryButtonClicked()
{
QModelIndexList selection = m_ui.searchDirectoryList->selectionModel()->selectedIndexes();
if (selection.size() < 1)
@ -280,17 +282,17 @@ void GameListSettingsWidget::onRemoveSearchDirectoryButtonPressed()
m_search_directories_model->removeEntry(row);
}
void GameListSettingsWidget::onRescanAllGamesPressed()
void GameListSettingsWidget::onRescanAllGamesClicked()
{
m_host_interface->refreshGameList(true, false);
}
void GameListSettingsWidget::onScanForNewGamesPressed()
void GameListSettingsWidget::onScanForNewGamesClicked()
{
m_host_interface->refreshGameList(false, false);
}
void GameListSettingsWidget::onUpdateRedumpDatabaseButtonPressed()
void GameListSettingsWidget::onUpdateRedumpDatabaseButtonClicked()
{
if (QMessageBox::question(this, tr("Download database from redump.org?"),
tr("Do you wish to download the disc database from redump.org?\n\nThis will download "

View file

@ -21,11 +21,11 @@ public Q_SLOTS:
private Q_SLOTS:
void onDirectoryListItemClicked(const QModelIndex& index);
void onAddSearchDirectoryButtonPressed();
void onRemoveSearchDirectoryButtonPressed();
void onScanForNewGamesPressed();
void onRescanAllGamesPressed();
void onUpdateRedumpDatabaseButtonPressed();
void onAddSearchDirectoryButtonClicked();
void onRemoveSearchDirectoryButtonClicked();
void onScanForNewGamesClicked();
void onRescanAllGamesClicked();
void onUpdateRedumpDatabaseButtonClicked();
protected:
void resizeEvent(QResizeEvent* event);

View file

@ -41,7 +41,7 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QToolButton" name="addSearchDirectoryButton">
<widget class="QPushButton" name="addSearchDirectoryButton">
<property name="text">
<string>Add</string>
</property>
@ -49,13 +49,10 @@
<iconset resource="resources/icons.qrc">
<normaloff>:/icons/list-add.png</normaloff>:/icons/list-add.png</iconset>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="removeSearchDirectoryButton">
<widget class="QPushButton" name="removeSearchDirectoryButton">
<property name="text">
<string>Remove</string>
</property>
@ -63,9 +60,6 @@
<iconset resource="resources/icons.qrc">
<normaloff>:/icons/list-remove.png</normaloff>:/icons/list-remove.png</iconset>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
</widget>
</item>
<item>
@ -82,7 +76,7 @@
</spacer>
</item>
<item>
<widget class="QToolButton" name="scanForNewGames">
<widget class="QPushButton" name="scanForNewGames">
<property name="text">
<string>Scan New</string>
</property>
@ -90,13 +84,10 @@
<iconset resource="resources/icons.qrc">
<normaloff>:/icons/folder-open.png</normaloff>:/icons/folder-open.png</iconset>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="rescanAllGames">
<widget class="QPushButton" name="rescanAllGames">
<property name="text">
<string>Rescan All</string>
</property>
@ -104,9 +95,6 @@
<iconset resource="resources/icons.qrc">
<normaloff>:/icons/view-refresh.png</normaloff>:/icons/view-refresh.png</iconset>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
</widget>
</item>
<item>

View file

@ -45,6 +45,8 @@ GPUSettingsWidget::GPUSettingsWidget(QtHostInterface* host_interface, QWidget* p
QStringLiteral("ForceNTSCTimings"));
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.linearTextureFiltering, QStringLiteral("GPU"),
QStringLiteral("TextureFiltering"));
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.widescreenHack, QStringLiteral("GPU"),
QStringLiteral("WidescreenHack"));
connect(m_ui.resolutionScale, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&GPUSettingsWidget::updateScaledDitheringEnabled);
@ -73,7 +75,7 @@ GPUSettingsWidget::GPUSettingsWidget(QtHostInterface* host_interface, QWidget* p
"Some games display content in the overscan area, or use it for screen effects and may "
"not display correctly with the All Borders setting. Only Overscan offers a good "
"compromise between stability and hiding black borders.");
dialog->registerWidgetHelp(m_ui.disableInterlacing, "Disable Interlacing (force progressive render/scan)", "Checked",
dialog->registerWidgetHelp(m_ui.disableInterlacing, "Disable Interlacing (force progressive render/scan)", "Unchecked",
"Forces the display of frames to progressive mode. This only affects the displayed image, "
"the console will be unaware of the setting. If the game is internally producing "
"interlaced frames, this option may not have any effect. Usually safe to enable.");
@ -115,6 +117,10 @@ GPUSettingsWidget::GPUSettingsWidget(QtHostInterface* host_interface, QWidget* p
"Smooths out the blockyness of magnified textures on 3D object by using bilinear "
"filtering. Will have a greater effect on higher resolution scales. Currently this option "
"produces artifacts around objects in many games and needs further work. Only applies to the hardware renderers.");
dialog->registerWidgetHelp(m_ui.widescreenHack, "Widescreen Hack", "Unchecked",
"Scales vertex positions in screen-space to a widescreen aspect ratio, essentially "
"increasing the field of view from 4:3 to 16:9 in 3D games. For 2D games, or games which "
"use pre-rendered backgrounds, this enhancement will not work as expected.");
}
GPUSettingsWidget::~GPUSettingsWidget() = default;

View file

@ -163,6 +163,13 @@
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QCheckBox" name="widescreenHack">
<property name="text">
<string>Widescreen Hack</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View file

@ -22,9 +22,10 @@ static constexpr std::array<const char*, static_cast<int>(SettingsDialog::Catego
"to populate the game list. Search directories can be added, removed, and switched to recursive/non-recursive. "
"Additionally, the redump.org database can be downloaded or updated to provide titles for discs, as the discs "
"themselves do not provide title information.",
"<strong>Hotkey Settings</strong><hr>Binding a hotkey allows you to trigger events such as a resetting, powering "
"off, taking screenshots or saving/loading states at the press of a key/controller button. Hotkey titles are "
"self-explanatory.",
"<strong>Hotkey Settings</strong><hr>Binding a hotkey allows you to trigger events such as a resetting or taking "
"screenshots at the press of a key/controller button. Hotkey titles are self-explanatory. Clicking a binding will "
"start a countdown, in which case you should press the key or controller button/axis you wish to bind. If no button "
"is pressed and the timer lapses, the binding will be unchanged. To clear a binding, right-click the button.",
"<strong>Controller Settings</strong><hr>This page lets you choose the type of controller you wish to simulate for "
"the console, and rebind the keys or host game controller buttons to your choosing. Clicking a binding will start a "
"countdown, in which case you should press the key or controller button/axis you wish to bind. (For rumble, press "

View file

@ -845,6 +845,7 @@ void SDLHostInterface::DrawQuickSettingsMenu()
settings_changed |= ImGui::MenuItem("Scaled Dithering", nullptr, &m_settings_copy.gpu_scaled_dithering);
settings_changed |= ImGui::MenuItem("Texture Filtering", nullptr, &m_settings_copy.gpu_texture_filtering);
settings_changed |= ImGui::MenuItem("Disable Interlacing", nullptr, &m_settings_copy.gpu_disable_interlacing);
settings_changed |= ImGui::MenuItem("Widescreen Hack", nullptr, &m_settings_copy.gpu_widescreen_hack);
settings_changed |= ImGui::MenuItem("Display Linear Filtering", nullptr, &m_settings_copy.display_linear_filtering);
settings_changed |= ImGui::MenuItem("Display Integer Scaling", nullptr, &m_settings_copy.display_integer_scaling);
@ -1296,6 +1297,7 @@ void SDLHostInterface::DrawSettingsWindow()
settings_changed |= ImGui::Checkbox("Texture Filtering", &m_settings_copy.gpu_texture_filtering);
settings_changed |= ImGui::Checkbox("Disable Interlacing", &m_settings_copy.gpu_disable_interlacing);
settings_changed |= ImGui::Checkbox("Force NTSC Timings", &m_settings_copy.gpu_force_ntsc_timings);
settings_changed |= ImGui::Checkbox("Widescreen Hack", &m_settings_copy.gpu_widescreen_hack);
}
ImGui::EndTabItem();