diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/GamePropertiesActivity.java b/android/app/src/main/java/com/github/stenzek/duckstation/GamePropertiesActivity.java index 9b47173c8..86165abca 100644 --- a/android/app/src/main/java/com/github/stenzek/duckstation/GamePropertiesActivity.java +++ b/android/app/src/main/java/com/github/stenzek/duckstation/GamePropertiesActivity.java @@ -135,6 +135,7 @@ public class GamePropertiesActivity extends AppCompatActivity { activity.createBooleanGameSetting(ps, "GPUForceNTSCTimings", R.string.settings_force_ntsc_timings); activity.createBooleanGameSetting(ps, "GPUWidescreenHack", R.string.settings_widescreen_hack); activity.createBooleanGameSetting(ps, "GPUPGXP", R.string.settings_pgxp_geometry_correction); + activity.createBooleanGameSetting(ps, "PGXPPreserveProjFP", R.string.settings_pgxp_preserve_projection_precision); activity.createBooleanGameSetting(ps, "GPUPGXPDepthBuffer", R.string.settings_pgxp_depth_buffer); setPreferenceScreen(ps); diff --git a/src/duckstation-qt/gamepropertiesdialog.cpp b/src/duckstation-qt/gamepropertiesdialog.cpp index 1e0e78fd2..2c972a3c4 100644 --- a/src/duckstation-qt/gamepropertiesdialog.cpp +++ b/src/duckstation-qt/gamepropertiesdialog.cpp @@ -406,6 +406,7 @@ void GamePropertiesDialog::populateGameSettings() populateBooleanUserSetting(m_ui.userWidescreenHack, gs.gpu_widescreen_hack); populateBooleanUserSetting(m_ui.userForce43For24Bit, gs.display_force_4_3_for_24bit); populateBooleanUserSetting(m_ui.userPGXP, gs.gpu_pgxp); + populateBooleanUserSetting(m_ui.userPGXPProjectionPrecision, gs.gpu_pgxp_projection_precision); populateBooleanUserSetting(m_ui.userPGXPDepthBuffer, gs.gpu_pgxp_depth_buffer); if (gs.controller_1_type.has_value()) @@ -601,6 +602,7 @@ void GamePropertiesDialog::connectUi() connectBooleanUserSetting(m_ui.userWidescreenHack, &m_game_settings.gpu_widescreen_hack); connectBooleanUserSetting(m_ui.userForce43For24Bit, &m_game_settings.display_force_4_3_for_24bit); connectBooleanUserSetting(m_ui.userPGXP, &m_game_settings.gpu_pgxp); + connectBooleanUserSetting(m_ui.userPGXPProjectionPrecision, &m_game_settings.gpu_pgxp_projection_precision); connectBooleanUserSetting(m_ui.userPGXPDepthBuffer, &m_game_settings.gpu_pgxp_depth_buffer); connect(m_ui.userControllerType1, QOverload::of(&QComboBox::currentIndexChanged), [this](int index) { diff --git a/src/duckstation-qt/gamepropertiesdialog.ui b/src/duckstation-qt/gamepropertiesdialog.ui index bd0e389b5..27a381609 100644 --- a/src/duckstation-qt/gamepropertiesdialog.ui +++ b/src/duckstation-qt/gamepropertiesdialog.ui @@ -417,6 +417,16 @@ + + + PGXP Preserve Projection Precision + + + true + + + + PGXP Depth Buffer diff --git a/src/frontend-common/game_list.h b/src/frontend-common/game_list.h index ed819b3cb..490370cc2 100644 --- a/src/frontend-common/game_list.h +++ b/src/frontend-common/game_list.h @@ -130,7 +130,7 @@ private: enum : u32 { GAME_LIST_CACHE_SIGNATURE = 0x45434C47, - GAME_LIST_CACHE_VERSION = 22 + GAME_LIST_CACHE_VERSION = 23 }; using DatabaseMap = std::unordered_map; diff --git a/src/frontend-common/game_settings.cpp b/src/frontend-common/game_settings.cpp index 5bf0f3853..9ba52eae6 100644 --- a/src/frontend-common/game_settings.cpp +++ b/src/frontend-common/game_settings.cpp @@ -127,9 +127,10 @@ bool Entry::LoadFromStream(ByteStream* stream) !ReadOptionalFromStream(stream, &gpu_scaled_dithering) || !ReadOptionalFromStream(stream, &gpu_force_ntsc_timings) || !ReadOptionalFromStream(stream, &gpu_texture_filter) || !ReadOptionalFromStream(stream, &gpu_widescreen_hack) || - !ReadOptionalFromStream(stream, &gpu_pgxp) || !ReadOptionalFromStream(stream, &gpu_pgxp_depth_buffer) || - !ReadOptionalFromStream(stream, &controller_1_type) || !ReadOptionalFromStream(stream, &controller_2_type) || - !ReadOptionalFromStream(stream, &memory_card_1_type) || !ReadOptionalFromStream(stream, &memory_card_2_type) || + !ReadOptionalFromStream(stream, &gpu_pgxp) || !ReadOptionalFromStream(stream, &gpu_pgxp_projection_precision) || + !ReadOptionalFromStream(stream, &gpu_pgxp_depth_buffer) || !ReadOptionalFromStream(stream, &controller_1_type) || + !ReadOptionalFromStream(stream, &controller_2_type) || !ReadOptionalFromStream(stream, &memory_card_1_type) || + !ReadOptionalFromStream(stream, &memory_card_2_type) || !ReadStringFromStream(stream, &memory_card_1_shared_path) || !ReadStringFromStream(stream, &memory_card_2_shared_path) || !ReadStringFromStream(stream, &input_profile_name)) { @@ -176,10 +177,10 @@ bool Entry::SaveToStream(ByteStream* stream) const WriteOptionalToStream(stream, gpu_per_sample_shading) && WriteOptionalToStream(stream, gpu_true_color) && WriteOptionalToStream(stream, gpu_scaled_dithering) && WriteOptionalToStream(stream, gpu_force_ntsc_timings) && WriteOptionalToStream(stream, gpu_texture_filter) && WriteOptionalToStream(stream, gpu_widescreen_hack) && - WriteOptionalToStream(stream, gpu_pgxp) && WriteOptionalToStream(stream, gpu_pgxp_depth_buffer) && - WriteOptionalToStream(stream, controller_1_type) && WriteOptionalToStream(stream, controller_2_type) && - WriteOptionalToStream(stream, memory_card_1_type) && WriteOptionalToStream(stream, memory_card_2_type) && - WriteStringToStream(stream, memory_card_1_shared_path) && + WriteOptionalToStream(stream, gpu_pgxp) && WriteOptionalToStream(stream, gpu_pgxp_projection_precision) && + WriteOptionalToStream(stream, gpu_pgxp_depth_buffer) && WriteOptionalToStream(stream, controller_1_type) && + WriteOptionalToStream(stream, controller_2_type) && WriteOptionalToStream(stream, memory_card_1_type) && + WriteOptionalToStream(stream, memory_card_2_type) && WriteStringToStream(stream, memory_card_1_shared_path) && WriteStringToStream(stream, memory_card_2_shared_path) && WriteStringToStream(stream, input_profile_name); } @@ -286,6 +287,9 @@ static void ParseIniSection(Entry* entry, const char* section, const CSimpleIniA cvalue = ini.GetValue(section, "GPUPGXP", nullptr); if (cvalue) entry->gpu_pgxp = StringUtil::FromChars(cvalue); + cvalue = ini.GetValue(section, "GPUPGXPPreserveProjFP", nullptr); + if (cvalue) + entry->gpu_pgxp_projection_precision = StringUtil::FromChars(cvalue); cvalue = ini.GetValue(section, "GPUPGXPDepthBuffer", nullptr); if (cvalue) entry->gpu_pgxp_depth_buffer = StringUtil::FromChars(cvalue); @@ -392,6 +396,8 @@ static void StoreIniSection(const Entry& entry, const char* section, CSimpleIniA ini.SetValue(section, "GPUWidescreenHack", entry.gpu_widescreen_hack.value() ? "true" : "false"); if (entry.gpu_pgxp.has_value()) ini.SetValue(section, "GPUPGXP", entry.gpu_pgxp.value() ? "true" : "false"); + if (entry.gpu_pgxp_projection_precision.has_value()) + ini.SetValue(section, "GPUPGXPPreserveProjFP", entry.gpu_pgxp_projection_precision.value() ? "true" : "false"); if (entry.gpu_pgxp_depth_buffer.has_value()) ini.SetValue(section, "GPUPGXPDepthBuffer", entry.gpu_pgxp_depth_buffer.value() ? "true" : "false"); @@ -440,6 +446,7 @@ u32 Entry::GetUserSettingsCount() const count += BoolToUInt32(gpu_texture_filter.has_value()); count += BoolToUInt32(gpu_widescreen_hack.has_value()); count += BoolToUInt32(gpu_pgxp.has_value()); + count += BoolToUInt32(gpu_pgxp_projection_precision.has_value()); count += BoolToUInt32(gpu_pgxp_depth_buffer.has_value()); count += BoolToUInt32(controller_1_type.has_value()); count += BoolToUInt32(controller_2_type.has_value()); @@ -579,6 +586,13 @@ static std::optional GetEntryValueForKey(const Entry& entry, const else return entry.gpu_pgxp.value() ? "true" : "false"; } + else if (key == "GPUPGXPPreserveProjFP") + { + if (!entry.gpu_pgxp_projection_precision.has_value()) + return std::nullopt; + else + return entry.gpu_pgxp_projection_precision.value() ? "true" : "false"; + } else if (key == "GPUPGXPDepthBuffer") { if (!entry.gpu_pgxp_depth_buffer.has_value()) @@ -789,6 +803,13 @@ static void SetEntryValueForKey(Entry& entry, const std::string_view& key, const else entry.gpu_pgxp = StringUtil::FromChars(value.value()).value_or(false); } + else if (key == "GPUPGXPPreserveProjFP") + { + if (!value.has_value()) + entry.gpu_pgxp_projection_precision.reset(); + else + entry.gpu_pgxp_projection_precision = StringUtil::FromChars(value.value()).value_or(false); + } else if (key == "GPUPGXPDepthBuffer") { if (!value.has_value()) @@ -1021,6 +1042,8 @@ void Entry::ApplySettings(bool display_osd_messages) const g_settings.gpu_widescreen_hack = gpu_widescreen_hack.value(); if (gpu_pgxp.has_value()) g_settings.gpu_pgxp_enable = gpu_pgxp.value(); + if (gpu_pgxp_projection_precision.has_value()) + g_settings.gpu_pgxp_preserve_proj_fp = gpu_pgxp_projection_precision.value(); if (gpu_pgxp_depth_buffer.has_value()) g_settings.gpu_pgxp_depth_buffer = gpu_pgxp_depth_buffer.value(); diff --git a/src/frontend-common/game_settings.h b/src/frontend-common/game_settings.h index 14bc34751..dc4b8fb52 100644 --- a/src/frontend-common/game_settings.h +++ b/src/frontend-common/game_settings.h @@ -70,6 +70,7 @@ struct Entry std::optional gpu_texture_filter; std::optional gpu_widescreen_hack; std::optional gpu_pgxp; + std::optional gpu_pgxp_projection_precision; std::optional gpu_pgxp_depth_buffer; std::optional controller_1_type; std::optional controller_2_type;