diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index 39a5fc645..94be506ee 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -446,6 +446,7 @@ void HostInterface::SetDefaultSettings(SettingsInterface& si) si.SetBoolValue("GPU", "PGXPVertexCache", false); si.SetBoolValue("GPU", "PGXPCPU", false); si.SetBoolValue("GPU", "PGXPPreserveProjFP", false); + si.SetFloatValue("GPU", "PGXPTolerance", -1.0f); si.SetStringValue("Display", "CropMode", Settings::GetDisplayCropModeName(Settings::DEFAULT_DISPLAY_CROP_MODE)); si.SetIntValue("Display", "ActiveStartOffset", 0); diff --git a/src/core/pgxp.cpp b/src/core/pgxp.cpp index 096ddcc98..67ce57295 100644 --- a/src/core/pgxp.cpp +++ b/src/core/pgxp.cpp @@ -718,13 +718,23 @@ PGXP_value* PGXP_GetCachedVertex(short sx, short sy) return NULL; } -static float TruncateVertexPosition(float p) +static ALWAYS_INLINE_RELEASE float TruncateVertexPosition(float p) { const s32 int_part = static_cast(p); const float int_part_f = static_cast(int_part); return static_cast(static_cast(int_part << 5) >> 5) + (p - int_part_f); } +static ALWAYS_INLINE_RELEASE bool IsWithinTolerance(float precise_x, float precise_y, int int_x, int int_y) +{ + const float tolerance = g_settings.gpu_pgxp_tolerance; + if (tolerance < 0.0f) + return true; + + return (std::abs(precise_x - static_cast(int_x)) <= tolerance && + std::abs(precise_y - static_cast(int_y)) <= tolerance); +} + bool GetPreciseVertex(u32 addr, u32 value, int x, int y, int xOffs, int yOffs, float* out_x, float* out_y, float* out_w) { const PGXP_value* vert = ReadMem(addr); @@ -734,9 +744,11 @@ bool GetPreciseVertex(u32 addr, u32 value, int x, int y, int xOffs, int yOffs, f *out_x = TruncateVertexPosition(vert->x) + static_cast(xOffs); *out_y = TruncateVertexPosition(vert->y) + static_cast(yOffs); *out_w = vert->z / 32768.0f; - - // This value does not have a valid W coordinate - return ((vert->flags & VALID_2) == VALID_2); + if (IsWithinTolerance(*out_x, *out_y, x, y)) + { + // check validity of z component + return ((vert->flags & VALID_2) == VALID_2); + } } else { @@ -752,18 +764,20 @@ bool GetPreciseVertex(u32 addr, u32 value, int x, int y, int xOffs, int yOffs, f *out_x = TruncateVertexPosition(vert->x) + static_cast(xOffs); *out_y = TruncateVertexPosition(vert->y) + static_cast(yOffs); *out_w = vert->z / 32768.0f; - return false; // iCB: Getting the wrong w component causes too great an error when using perspective correction - // so disable it - } - else - { - // no valid value can be found anywhere, use the native PSX data - *out_x = static_cast(x); - *out_y = static_cast(y); - *out_w = 1.0f; - return false; + + if (IsWithinTolerance(*out_x, *out_y, x, y)) + { + return false; // iCB: Getting the wrong w component causes too great an error when using perspective correction + // so disable it + } } } + + // no valid value can be found anywhere, use the native PSX data + *out_x = static_cast(x); + *out_y = static_cast(y); + *out_w = 1.0f; + return false; } // pgxp_cpu.c diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 8dadf8aca..3dd9f51d0 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -158,6 +158,7 @@ void Settings::Load(SettingsInterface& si) gpu_pgxp_vertex_cache = si.GetBoolValue("GPU", "PGXPVertexCache", false); gpu_pgxp_cpu = si.GetBoolValue("GPU", "PGXPCPU", false); gpu_pgxp_preserve_proj_fp = si.GetBoolValue("GPU", "PGXPPreserveProjFP", false); + gpu_pgxp_tolerance = si.GetFloatValue("GPU", "PGXPTolerance", -1.0f); display_crop_mode = ParseDisplayCropMode( @@ -290,6 +291,7 @@ void Settings::Save(SettingsInterface& si) const si.SetBoolValue("GPU", "PGXPVertexCache", gpu_pgxp_vertex_cache); si.SetBoolValue("GPU", "PGXPCPU", gpu_pgxp_cpu); si.SetBoolValue("GPU", "PGXPPreserveProjFP", gpu_pgxp_preserve_proj_fp); + si.SetFloatValue("GPU", "PGXPTolerance", gpu_pgxp_tolerance); si.SetStringValue("Display", "CropMode", GetDisplayCropModeName(display_crop_mode)); si.SetIntValue("Display", "ActiveStartOffset", display_active_start_offset); diff --git a/src/core/settings.h b/src/core/settings.h index da879b4ff..fb3fb9084 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -110,9 +110,9 @@ struct Settings bool gpu_pgxp_cpu = false; bool gpu_pgxp_preserve_proj_fp = false; DisplayCropMode display_crop_mode = DisplayCropMode::None; + DisplayAspectRatio display_aspect_ratio = DisplayAspectRatio::R4_3; s16 display_active_start_offset = 0; s16 display_active_end_offset = 0; - DisplayAspectRatio display_aspect_ratio = DisplayAspectRatio::R4_3; bool display_force_4_3_for_24bit = false; bool gpu_24bit_chroma_smoothing = false; bool display_linear_filtering = true; @@ -125,6 +125,7 @@ struct Settings bool display_show_resolution = false; bool video_sync_enabled = true; float display_max_fps = 0.0f; + float gpu_pgxp_tolerance = -1.0f; bool cdrom_read_thread = true; bool cdrom_region_check = true; diff --git a/src/duckstation-qt/advancedsettingswidget.cpp b/src/duckstation-qt/advancedsettingswidget.cpp index ae7ce56f1..85af7d448 100644 --- a/src/duckstation-qt/advancedsettingswidget.cpp +++ b/src/duckstation-qt/advancedsettingswidget.cpp @@ -57,6 +57,34 @@ static void setIntRangeTweakOption(QTableWidget* table, int row, int value) cb->setValue(value); } +static void addFloatRangeTweakOption(QtHostInterface* host_interface, QTableWidget* table, QString name, + std::string section, std::string key, float min_value, float max_value, + float step_value, float default_value) +{ + const int row = table->rowCount(); + + table->insertRow(row); + + QTableWidgetItem* name_item = new QTableWidgetItem(name); + name_item->setFlags(name_item->flags() & ~(Qt::ItemIsEditable | Qt::ItemIsSelectable)); + table->setItem(row, 0, name_item); + + QDoubleSpinBox* cb = new QDoubleSpinBox(table); + cb->setMinimum(min_value); + cb->setMaximum(max_value); + cb->setSingleStep(step_value); + SettingWidgetBinder::BindWidgetToFloatSetting(host_interface, cb, std::move(section), std::move(key), default_value); + table->setCellWidget(row, 1, cb); +} + +static void setFloatRangeTweakOption(QTableWidget* table, int row, float value) +{ + QWidget* widget = table->cellWidget(row, 1); + QDoubleSpinBox* cb = qobject_cast(widget); + Assert(cb); + cb->setValue(value); +} + template static void addChoiceTweakOption(QtHostInterface* host_interface, QTableWidget* table, QString name, std::string section, std::string key, std::optional (*parse_callback)(const char*), @@ -121,6 +149,8 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(QtHostInterface* host_interface, addBooleanTweakOption(m_host_interface, m_ui.tweakOptionTable, tr("PGXP CPU Mode"), "GPU", "PGXPCPU", false); addBooleanTweakOption(m_host_interface, m_ui.tweakOptionTable, tr("PGXP Preserve Projection Precision"), "GPU", "PGXPPreserveProjFP", false); + addFloatRangeTweakOption(m_host_interface, m_ui.tweakOptionTable, tr("PGXP Geometry Tolerance"), "GPU", + "PGXPTolerance", -1.0f, 10.0f, 0.5f, -1.0f); addBooleanTweakOption(m_host_interface, m_ui.tweakOptionTable, tr("Enable Recompiler Memory Exceptions"), "CPU", "RecompilerMemoryExceptions", false); @@ -154,14 +184,15 @@ void AdvancedSettingsWidget::onResetToDefaultClicked() setBooleanTweakOption(m_ui.tweakOptionTable, 0, false); setBooleanTweakOption(m_ui.tweakOptionTable, 1, false); setBooleanTweakOption(m_ui.tweakOptionTable, 2, false); - setBooleanTweakOption(m_ui.tweakOptionTable, 3, false); - setChoiceTweakOption(m_ui.tweakOptionTable, 4, Settings::DEFAULT_CPU_FASTMEM_MODE); - setBooleanTweakOption(m_ui.tweakOptionTable, 5, false); - setIntRangeTweakOption(m_ui.tweakOptionTable, 6, static_cast(Settings::DEFAULT_DMA_MAX_SLICE_TICKS)); - setIntRangeTweakOption(m_ui.tweakOptionTable, 7, static_cast(Settings::DEFAULT_DMA_HALT_TICKS)); - setIntRangeTweakOption(m_ui.tweakOptionTable, 8, static_cast(Settings::DEFAULT_GPU_FIFO_SIZE)); - setIntRangeTweakOption(m_ui.tweakOptionTable, 9, static_cast(Settings::DEFAULT_GPU_MAX_RUN_AHEAD)); - setBooleanTweakOption(m_ui.tweakOptionTable, 10, false); - setIntRangeTweakOption(m_ui.tweakOptionTable, 11, 0); - setBooleanTweakOption(m_ui.tweakOptionTable, 12, true); + setFloatRangeTweakOption(m_ui.tweakOptionTable, 3, -1.0f); + setBooleanTweakOption(m_ui.tweakOptionTable, 4, false); + setChoiceTweakOption(m_ui.tweakOptionTable, 5, Settings::DEFAULT_CPU_FASTMEM_MODE); + setBooleanTweakOption(m_ui.tweakOptionTable, 6, false); + setIntRangeTweakOption(m_ui.tweakOptionTable, 7, static_cast(Settings::DEFAULT_DMA_MAX_SLICE_TICKS)); + setIntRangeTweakOption(m_ui.tweakOptionTable, 8, static_cast(Settings::DEFAULT_DMA_HALT_TICKS)); + setIntRangeTweakOption(m_ui.tweakOptionTable, 9, static_cast(Settings::DEFAULT_GPU_FIFO_SIZE)); + setIntRangeTweakOption(m_ui.tweakOptionTable, 10, static_cast(Settings::DEFAULT_GPU_MAX_RUN_AHEAD)); + setBooleanTweakOption(m_ui.tweakOptionTable, 11, false); + setIntRangeTweakOption(m_ui.tweakOptionTable, 12, 0); + setBooleanTweakOption(m_ui.tweakOptionTable, 13, true); }