From 362905e3df0c2b01d414528dd2bf92ec3539cb68 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Thu, 3 Dec 2020 22:31:21 +1000 Subject: [PATCH] GPU: Add display line offset game setting Use when games need additional cropping. --- data/database/gamesettings.ini | 5 ++ src/core/gpu.cpp | 16 +++--- src/core/host_interface.cpp | 6 +- src/core/settings.cpp | 4 ++ src/core/settings.h | 6 ++ .../libretro_host_interface.cpp | 41 +++++++++++++- src/duckstation-qt/gamepropertiesdialog.cpp | 24 ++++++++ src/duckstation-qt/gamepropertiesdialog.ui | 55 ++++++++++++++++--- src/frontend-common/game_list.h | 2 +- src/frontend-common/game_settings.cpp | 27 +++++++-- src/frontend-common/game_settings.h | 2 + 11 files changed, 163 insertions(+), 25 deletions(-) diff --git a/data/database/gamesettings.ini b/data/database/gamesettings.ini index e9ddfe58c..8c5a280b5 100644 --- a/data/database/gamesettings.ini +++ b/data/database/gamesettings.ini @@ -462,3 +462,8 @@ GPUMaxRunAhead = 1 # SLUS-00022 (Slam 'n Jam '96 featuring Magic & Kareem (USA)) [SLUS-00022] DisableUpscaling = true + + +# SCES-01224 (Blasto (Europe) (En,Fr,De,Es,It)) +[SCES-01224] +DisplayLineStartOffset = 1 diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index b35d822c2..65d5406d5 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -545,15 +545,15 @@ void GPU::UpdateCRTCDisplayParameters() case DisplayCropMode::None: cs.horizontal_active_start = static_cast(std::max(0, 487 + g_settings.display_active_start_offset)); cs.horizontal_active_end = static_cast(std::max(0, 3282 + g_settings.display_active_end_offset)); - cs.vertical_active_start = 20; - cs.vertical_active_end = 308; + cs.vertical_active_start = static_cast(std::max(0, 20 + g_settings.display_line_start_offset)); + cs.vertical_active_end = static_cast(std::max(0, 308 + g_settings.display_line_end_offset)); break; case DisplayCropMode::Overscan: cs.horizontal_active_start = static_cast(std::max(0, 628 + g_settings.display_active_start_offset)); cs.horizontal_active_end = static_cast(std::max(0, 3188 + g_settings.display_active_end_offset)); - cs.vertical_active_start = 30; - cs.vertical_active_end = 298; + cs.vertical_active_start = static_cast(std::max(0, 30 + g_settings.display_line_start_offset)); + cs.vertical_active_end = static_cast(std::max(0, 298 + g_settings.display_line_end_offset)); break; case DisplayCropMode::Borders: @@ -572,15 +572,15 @@ void GPU::UpdateCRTCDisplayParameters() case DisplayCropMode::None: cs.horizontal_active_start = static_cast(std::max(0, 488 + g_settings.display_active_start_offset)); cs.horizontal_active_end = static_cast(std::max(0, 3288 + g_settings.display_active_end_offset)); - cs.vertical_active_start = 16; - cs.vertical_active_end = 256; + cs.vertical_active_start = static_cast(std::max(0, 16 + g_settings.display_line_start_offset)); + cs.vertical_active_end = static_cast(std::max(0, 256 + g_settings.display_line_end_offset)); break; case DisplayCropMode::Overscan: cs.horizontal_active_start = static_cast(std::max(0, 608 + g_settings.display_active_start_offset)); cs.horizontal_active_end = static_cast(std::max(0, 3168 + g_settings.display_active_end_offset)); - cs.vertical_active_start = 24; - cs.vertical_active_end = 248; + cs.vertical_active_start = static_cast(std::max(0, 24 + g_settings.display_line_start_offset)); + cs.vertical_active_end = static_cast(std::max(0, 248 + g_settings.display_line_end_offset)); break; case DisplayCropMode::Borders: diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index c644ccafd..d2dd46805 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -451,6 +451,8 @@ void HostInterface::SetDefaultSettings(SettingsInterface& si) si.SetStringValue("Display", "CropMode", Settings::GetDisplayCropModeName(Settings::DEFAULT_DISPLAY_CROP_MODE)); si.SetIntValue("Display", "ActiveStartOffset", 0); si.SetIntValue("Display", "ActiveEndOffset", 0); + si.SetIntValue("Display", "LineStartOffset", 0); + si.SetIntValue("Display", "LineEndOffset", 0); si.SetStringValue("Display", "AspectRatio", Settings::GetDisplayAspectRatioName(Settings::DEFAULT_DISPLAY_ASPECT_RATIO)); si.SetBoolValue("Display", "Force4_3For24Bit", false); @@ -652,7 +654,9 @@ void HostInterface::CheckForSettingsChanges(const Settings& old_settings) g_settings.display_aspect_ratio != old_settings.display_aspect_ratio || g_settings.gpu_pgxp_enable != old_settings.gpu_pgxp_enable || g_settings.display_active_start_offset != old_settings.display_active_start_offset || - g_settings.display_active_end_offset != old_settings.display_active_end_offset) + g_settings.display_active_end_offset != old_settings.display_active_end_offset || + g_settings.display_line_start_offset != old_settings.display_line_start_offset || + g_settings.display_line_end_offset != old_settings.display_line_end_offset) { g_gpu->UpdateSettings(); } diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 5451601aa..5c621e18f 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -171,6 +171,8 @@ void Settings::Load(SettingsInterface& si) display_force_4_3_for_24bit = si.GetBoolValue("Display", "Force4_3For24Bit", false); display_active_start_offset = static_cast(si.GetIntValue("Display", "ActiveStartOffset", 0)); display_active_end_offset = static_cast(si.GetIntValue("Display", "ActiveEndOffset", 0)); + display_line_start_offset = static_cast(si.GetIntValue("Display", "LineStartOffset", 0)); + display_line_end_offset = static_cast(si.GetIntValue("Display", "LineEndOffset", 0)); display_linear_filtering = si.GetBoolValue("Display", "LinearFiltering", true); display_integer_scaling = si.GetBoolValue("Display", "IntegerScaling", false); display_post_processing = si.GetBoolValue("Display", "PostProcessing", false); @@ -296,6 +298,8 @@ void Settings::Save(SettingsInterface& si) const si.SetStringValue("Display", "CropMode", GetDisplayCropModeName(display_crop_mode)); si.SetIntValue("Display", "ActiveStartOffset", display_active_start_offset); si.SetIntValue("Display", "ActiveEndOffset", display_active_end_offset); + si.SetIntValue("Display", "LineStartOffset", display_line_start_offset); + si.SetIntValue("Display", "LineEndOffset", display_line_end_offset); si.SetBoolValue("Display", "Force4_3For24Bit", display_force_4_3_for_24bit); si.SetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(display_aspect_ratio)); si.SetBoolValue("Display", "LinearFiltering", display_linear_filtering); diff --git a/src/core/settings.h b/src/core/settings.h index fb3fb9084..75811d1c7 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -113,6 +113,12 @@ struct Settings DisplayAspectRatio display_aspect_ratio = DisplayAspectRatio::R4_3; s16 display_active_start_offset = 0; s16 display_active_end_offset = 0; + s8 display_line_start_offset = 0; + s8 display_line_end_offset = 0; + s8 display_crop_left = 0; + s8 display_crop_right = 0; + s8 display_crop_top = 0; + s8 display_crop_bottom = 0; bool display_force_4_3_for_24bit = false; bool gpu_24bit_chroma_smoothing = false; bool display_linear_filtering = true; diff --git a/src/duckstation-libretro/libretro_host_interface.cpp b/src/duckstation-libretro/libretro_host_interface.cpp index 57fa7528f..3525cb378 100644 --- a/src/duckstation-libretro/libretro_host_interface.cpp +++ b/src/duckstation-libretro/libretro_host_interface.cpp @@ -489,7 +489,7 @@ void LibretroHostInterface::OnSystemDestroyed() m_using_hardware_renderer = false; } -static std::array s_option_definitions = {{ +static std::array s_option_definitions = {{ {"duckstation_Console.Region", "Console Region", "Determines which region/hardware to emulate. Auto-Detect will use the region of the disc inserted.", @@ -834,6 +834,45 @@ static std::array s_option_definitions = {{ "LUT" #endif }, + {"duckstation_Display.LineStartOffset", + "Display Line Start Offset", + "Pads or crops off lines from the top of the displayed image.", + {{"-30", "-30"}, {"-29", "-29"}, {"-28", "-28"}, {"-27", "-27"}, {"-26", "-26"}, {"-25", "-25"}, {"-24", "-24"}, + {"-23", "-23"}, {"-22", "-22"}, {"-21", "-21"}, {"-20", "-20"}, {"-19", "-19"}, {"-18", "-18"}, {"-17", "-17"}, + {"-16", "-16"}, {"-15", "-15"}, {"-14", "-14"}, {"-13", "-13"}, {"-12", "-12"}, {"-11", "-11"}, {"-10", "-10"}, + {"-9", "-9"}, {"-8", "-8"}, {"-7", "-7"}, {"-6", "-6"}, {"-5", "-5"}, {"-4", "-4"}, {"-3", "-3"}, + {"-2", "-2"}, {"-1", "-1"}, {"0", "0"}, {"1", "1"}, {"2", "2"}, {"3", "3"}, {"4", "4"}, + {"5", "5"}, {"6", "6"}, {"7", "7"}, {"8", "8"}, {"9", "9"}, {"10", "10"}, {"11", "11"}, + {"12", "12"}, {"13", "13"}, {"14", "14"}, {"15", "15"}, {"16", "16"}, {"17", "17"}, {"18", "18"}, + {"19", "19"}, {"20", "20"}, {"21", "21"}, {"22", "22"}, {"23", "23"}, {"24", "24"}, {"25", "25"}, + {"26", "26"}, {"27", "27"}, {"28", "28"}, {"29", "29"}, {"30", "30"}}, + "0"}, + {"duckstation_Display.LineEndOffset", + "Display Line End Offset", + "Pads or crops off lines from the bottom of the displayed image.", + {{"-30", "-30"}, {"-29", "-29"}, {"-28", "-28"}, {"-27", "-27"}, {"-26", "-26"}, {"-25", "-25"}, {"-24", "-24"}, + {"-23", "-23"}, {"-22", "-22"}, {"-21", "-21"}, {"-20", "-20"}, {"-19", "-19"}, {"-18", "-18"}, {"-17", "-17"}, + {"-16", "-16"}, {"-15", "-15"}, {"-14", "-14"}, {"-13", "-13"}, {"-12", "-12"}, {"-11", "-11"}, {"-10", "-10"}, + {"-9", "-9"}, {"-8", "-8"}, {"-7", "-7"}, {"-6", "-6"}, {"-5", "-5"}, {"-4", "-4"}, {"-3", "-3"}, + {"-2", "-2"}, {"-1", "-1"}, {"0", "0"}, {"1", "1"}, {"2", "2"}, {"3", "3"}, {"4", "4"}, + {"5", "5"}, {"6", "6"}, {"7", "7"}, {"8", "8"}, {"9", "9"}, {"10", "10"}, {"11", "11"}, + {"12", "12"}, {"13", "13"}, {"14", "14"}, {"15", "15"}, {"16", "16"}, {"17", "17"}, {"18", "18"}, + {"19", "19"}, {"20", "20"}, {"21", "21"}, {"22", "22"}, {"23", "23"}, {"24", "24"}, {"25", "25"}, + {"26", "26"}, {"27", "27"}, {"28", "28"}, {"29", "29"}, {"30", "30"}}, + "0"}, + {"duckstation_GPU.PGXPTolerance", + "PGXP Geometry Tolerance", + "Ignores precise positions if the difference exceeds this threshold.", + { + {"-1.0", "None"}, {"0.5", "0.5 pixels"}, {"1.0", "1.0 pixels"}, {"1.5", "1.5 pixels"}, + {"2.0", "2.0 pixels"}, {"2.5", "2.5 pixels"}, {"3.0", "3.0 pixels"}, {"3.5", "3.5 pixels"}, + {"4.0", "4.0 pixels"}, {"4.5", "4.5 pixels"}, {"5.0", "5.0 pixels"}, {"5.5", "5.5 pixels"}, + {"6.0", "6.0 pixels"}, {"6.5", "6.5 pixels"}, {"7.0", "7.0 pixels"}, {"7.5", "7.5 pixels"}, + {"8.0", "8.0 pixels"}, {"8.5", "8.5 pixels"}, {"9.0", "9.0 pixels"}, {"9.5", "9.0 pixels"}, + {"10.0", "10.0 pixels"}, + + }, + "-1.0"}, {}, }}; diff --git a/src/duckstation-qt/gamepropertiesdialog.cpp b/src/duckstation-qt/gamepropertiesdialog.cpp index 3a765cbb9..15ce96d2e 100644 --- a/src/duckstation-qt/gamepropertiesdialog.cpp +++ b/src/duckstation-qt/gamepropertiesdialog.cpp @@ -289,6 +289,16 @@ void GamePropertiesDialog::populateGameSettings() QSignalBlocker sb(m_ui.displayActiveEndOffset); m_ui.displayActiveEndOffset->setValue(static_cast(gs.display_active_end_offset.value())); } + if (gs.display_line_start_offset.has_value()) + { + QSignalBlocker sb(m_ui.displayLineStartOffset); + m_ui.displayLineStartOffset->setValue(static_cast(gs.display_line_start_offset.value())); + } + if (gs.display_line_end_offset.has_value()) + { + QSignalBlocker sb(m_ui.displayLineEndOffset); + m_ui.displayLineEndOffset->setValue(static_cast(gs.display_line_end_offset.value())); + } if (gs.dma_max_slice_ticks.has_value()) { @@ -645,6 +655,20 @@ void GamePropertiesDialog::connectUi() m_game_settings.display_active_end_offset = static_cast(value); saveGameSettings(); }); + connect(m_ui.displayLineStartOffset, QOverload::of(&QSpinBox::valueChanged), [this](int value) { + if (value == 0) + m_game_settings.display_line_start_offset.reset(); + else + m_game_settings.display_line_start_offset = static_cast(value); + saveGameSettings(); + }); + connect(m_ui.displayLineEndOffset, QOverload::of(&QSpinBox::valueChanged), [this](int value) { + if (value == 0) + m_game_settings.display_line_end_offset.reset(); + else + m_game_settings.display_line_end_offset = static_cast(value); + saveGameSettings(); + }); connect(m_ui.dmaMaxSliceTicks, QOverload::of(&QSpinBox::valueChanged), [this](int value) { if (value == 0) m_game_settings.dma_max_slice_ticks.reset(); diff --git a/src/duckstation-qt/gamepropertiesdialog.ui b/src/duckstation-qt/gamepropertiesdialog.ui index 00cafef5e..b078f8757 100644 --- a/src/duckstation-qt/gamepropertiesdialog.ui +++ b/src/duckstation-qt/gamepropertiesdialog.ui @@ -687,13 +687,50 @@ + + + Display Line Offset: + + + + + + + + + -128 + + + 127 + + + 0 + + + + + + + -128 + + + 127 + + + 0 + + + + + + DMA Max Slice Ticks: - + 10000 @@ -703,14 +740,14 @@ - + DMA Halt Ticks: - + 1000 @@ -720,28 +757,28 @@ - + GPU FIFO Size: - + 128 - + GPU Max Run Ahead: - + 1000 @@ -751,14 +788,14 @@ - + PGXP Geometry Tolerance: - + -1 diff --git a/src/frontend-common/game_list.h b/src/frontend-common/game_list.h index 858a618f3..504a42451 100644 --- a/src/frontend-common/game_list.h +++ b/src/frontend-common/game_list.h @@ -108,7 +108,7 @@ private: enum : u32 { GAME_LIST_CACHE_SIGNATURE = 0x45434C47, - GAME_LIST_CACHE_VERSION = 15 + GAME_LIST_CACHE_VERSION = 16 }; using DatabaseMap = std::unordered_map; diff --git a/src/frontend-common/game_settings.cpp b/src/frontend-common/game_settings.cpp index fbaf27beb..f4fc275a5 100644 --- a/src/frontend-common/game_settings.cpp +++ b/src/frontend-common/game_settings.cpp @@ -111,6 +111,8 @@ bool Entry::LoadFromStream(ByteStream* stream) !ReadOptionalFromStream(stream, &cpu_overclock_enable) || !ReadOptionalFromStream(stream, &cdrom_read_speedup) || !ReadOptionalFromStream(stream, &display_active_start_offset) || !ReadOptionalFromStream(stream, &display_active_end_offset) || + !ReadOptionalFromStream(stream, &display_line_start_offset) || + !ReadOptionalFromStream(stream, &display_line_end_offset) || !ReadOptionalFromStream(stream, &dma_max_slice_ticks) || !ReadOptionalFromStream(stream, &dma_halt_ticks) || !ReadOptionalFromStream(stream, &gpu_fifo_size) || !ReadOptionalFromStream(stream, &gpu_max_run_ahead) || !ReadOptionalFromStream(stream, &gpu_pgxp_tolerance) || !ReadOptionalFromStream(stream, &display_crop_mode) || @@ -158,10 +160,11 @@ bool Entry::SaveToStream(ByteStream* stream) const WriteOptionalToStream(stream, cpu_overclock_enable) && WriteOptionalToStream(stream, cdrom_read_speedup) && WriteOptionalToStream(stream, display_active_start_offset) && WriteOptionalToStream(stream, display_active_end_offset) && - WriteOptionalToStream(stream, dma_max_slice_ticks) && WriteOptionalToStream(stream, dma_halt_ticks) && - WriteOptionalToStream(stream, gpu_fifo_size) && WriteOptionalToStream(stream, gpu_max_run_ahead) && - WriteOptionalToStream(stream, gpu_pgxp_tolerance) && WriteOptionalToStream(stream, display_crop_mode) && - WriteOptionalToStream(stream, display_aspect_ratio) && + WriteOptionalToStream(stream, display_line_start_offset) && + WriteOptionalToStream(stream, display_line_end_offset) && WriteOptionalToStream(stream, dma_max_slice_ticks) && + WriteOptionalToStream(stream, dma_halt_ticks) && WriteOptionalToStream(stream, gpu_fifo_size) && + WriteOptionalToStream(stream, gpu_max_run_ahead) && WriteOptionalToStream(stream, gpu_pgxp_tolerance) && + WriteOptionalToStream(stream, display_crop_mode) && WriteOptionalToStream(stream, display_aspect_ratio) && WriteOptionalToStream(stream, display_linear_upscaling) && WriteOptionalToStream(stream, display_integer_upscaling) && WriteOptionalToStream(stream, display_force_4_3_for_24bit) && @@ -204,7 +207,13 @@ static void ParseIniSection(Entry* entry, const char* section, const CSimpleIniA entry->display_active_start_offset = static_cast(lvalue); lvalue = ini.GetLongValue(section, "DisplayActiveEndOffset", 0); if (lvalue != 0) - entry->display_active_end_offset = static_cast(lvalue); + entry->display_active_end_offset = static_cast(lvalue); + lvalue = ini.GetLongValue(section, "DisplayLineStartOffset", 0); + if (lvalue != 0) + entry->display_line_start_offset = static_cast(lvalue); + lvalue = ini.GetLongValue(section, "DisplayLineEndOffset", 0); + if (lvalue != 0) + entry->display_line_end_offset = static_cast(lvalue); lvalue = ini.GetLongValue(section, "DMAMaxSliceTicks", 0); if (lvalue > 0) entry->dma_max_slice_ticks = static_cast(lvalue); @@ -311,6 +320,10 @@ static void StoreIniSection(const Entry& entry, const char* section, CSimpleIniA ini.SetLongValue(section, "DisplayActiveStartOffset", entry.display_active_start_offset.value()); if (entry.display_active_end_offset.has_value()) ini.SetLongValue(section, "DisplayActiveEndOffset", entry.display_active_end_offset.value()); + if (entry.display_line_start_offset.has_value()) + ini.SetLongValue(section, "DisplayLineStartOffset", entry.display_line_start_offset.value()); + if (entry.display_line_end_offset.has_value()) + ini.SetLongValue(section, "DisplayLineEndOffset", entry.display_line_end_offset.value()); if (entry.dma_max_slice_ticks.has_value()) ini.SetLongValue(section, "DMAMaxSliceTicks", static_cast(entry.dma_max_slice_ticks.value())); if (entry.dma_halt_ticks.has_value()) @@ -488,6 +501,10 @@ void Entry::ApplySettings(bool display_osd_messages) const g_settings.display_active_start_offset = display_active_start_offset.value(); if (display_active_end_offset.has_value()) g_settings.display_active_end_offset = display_active_end_offset.value(); + if (display_line_start_offset.has_value()) + g_settings.display_line_start_offset = display_line_start_offset.value(); + if (display_line_end_offset.has_value()) + g_settings.display_line_end_offset = display_line_end_offset.value(); if (dma_max_slice_ticks.has_value()) g_settings.dma_max_slice_ticks = dma_max_slice_ticks.value(); if (dma_halt_ticks.has_value()) diff --git a/src/frontend-common/game_settings.h b/src/frontend-common/game_settings.h index dab77367f..16d3160d6 100644 --- a/src/frontend-common/game_settings.h +++ b/src/frontend-common/game_settings.h @@ -39,6 +39,8 @@ struct Entry std::bitset(Trait::Count)> traits{}; std::optional display_active_start_offset; std::optional display_active_end_offset; + std::optional display_line_start_offset; + std::optional display_line_end_offset; std::optional dma_max_slice_ticks; std::optional dma_halt_ticks; std::optional gpu_fifo_size;