Skip to content

Commit

Permalink
GS: Add Pre-Round Sprite hack
Browse files Browse the repository at this point in the history
This attempts to preproduce hardware behaviour, but falls down in a bunch of cases, hence the hack.
  • Loading branch information
refractionpcsx2 committed Jun 30, 2022
1 parent 6daeb56 commit cf5a3d6
Show file tree
Hide file tree
Showing 11 changed files with 104 additions and 25 deletions.
1 change: 1 addition & 0 deletions pcsx2-qt/Settings/GraphicsSettingsWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.PCRTCOverscan, "EmuCore/GS", "pcrtc_overscan", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.PCRTCAntiBlur, "EmuCore/GS", "pcrtc_antiblur", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.DisableInterlaceOffset, "EmuCore/GS", "disable_interlace_offset", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.PreRoundSprites, "EmuCore/GS", "preround_sprites", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.internalResolutionScreenshots, "EmuCore/GS", "InternalResolutionScreenshots", false);
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.zoom, "EmuCore/GS", "Zoom", 100.0f);
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.stretchY, "EmuCore/GS", "StretchY", 100.0f);
Expand Down
56 changes: 33 additions & 23 deletions pcsx2-qt/Settings/GraphicsSettingsWidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>657</width>
<width>652</width>
<height>890</height>
</rect>
</property>
Expand Down Expand Up @@ -278,31 +278,47 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="integerScaling">
<property name="text">
<string>Integer Upscaling</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="bilinearFiltering">
<property name="text">
<string>Bilinear Filtering</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="internalResolutionScreenshots">
<item row="4" column="0">
<widget class="QCheckBox" name="DisableInterlaceOffset">
<property name="toolTip">
<string>Disables interlacing offset which may reduce blurring in some situations.</string>
</property>
<property name="text">
<string>Internal Resolution Screenshots</string>
<string>Disable Interlace Offset</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="integerScaling">
<item row="1" column="1">
<widget class="QCheckBox" name="internalResolutionScreenshots">
<property name="text">
<string>Integer Upscaling</string>
<string>Internal Resolution Screenshots</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="PCRTCOverscan">
<item row="4" column="1">
<widget class="QCheckBox" name="PCRTCAntiBlur">
<property name="toolTip">
<string>Enables internal Anti-Blur hacks. Less accurate to PS2 rendering but will make a lot of games look less blurry.</string>
</property>
<property name="text">
<string>Show Overscan</string>
<string>Anti-Blur</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
</widget>
</item>
Expand All @@ -313,26 +329,20 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="DisableInterlaceOffset">
<property name="toolTip">
<string>Disables interlacing offset which may reduce blurring in some situations.</string>
</property>
<item row="2" column="1">
<widget class="QCheckBox" name="PCRTCOverscan">
<property name="text">
<string>Disable Interlace Offset</string>
<string>Show Overscan</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="PCRTCAntiBlur">
<item row="5" column="0">
<widget class="QCheckBox" name="PreRoundSprites">
<property name="toolTip">
<string>Enables internal Anti-Blur hacks. Less accurate to PS2 rendering but will make a lot of games look less blurry.</string>
<string>Attempts to pre-round sprite texel coordinates to resolve rounding issues. Helpful for games such as Beyond Good and Evil, and Manhunt</string>
</property>
<property name="text">
<string>Anti-Blur</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
<string>Pre-Round Sprites</string>
</property>
</widget>
</item>
Expand Down
1 change: 1 addition & 0 deletions pcsx2/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ struct Pcsx2Config
Mipmap : 1,
AA1 : 1,
PointListPalette : 1,
PreRoundSprites : 1,
ManualUserHacks : 1,
UserHacks_AlignSpriteX : 1,
UserHacks_AutoFlush : 1,
Expand Down
1 change: 1 addition & 0 deletions pcsx2/GS/GS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1488,6 +1488,7 @@ void GSApp::Init()
m_default_configuration["paltex"] = "0";
m_default_configuration["png_compression_level"] = std::to_string(Z_BEST_SPEED);
m_default_configuration["PointListPalette"] = "0";
m_default_configuration["preround_sprites"] = "0";
m_default_configuration["PrecacheTextureReplacements"] = "0";
m_default_configuration["preload_frame_with_gs_data"] = "0";
m_default_configuration["Renderer"] = std::to_string(static_cast<int>(GSRendererType::Auto));
Expand Down
56 changes: 54 additions & 2 deletions pcsx2/GS/GSState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1830,6 +1830,58 @@ void GSState::FlushPrim()
ASSERT((int)unused < GSUtil::GetVertexCount(PRIM->PRIM));
}

// Texel coordinate rounding
// Helps Beyond Good & Evil (water) and Manhunt (lights shining through objects).
// Dark Cloud 2 also benefits in some ways but is broken in others.
// Can help with some alignment issues when upscaling too, and is for both Software and Hardware renderers.
// This is *NOT* 100% safe, some games hate it (Gran Turismo 4's post processing for example).
// I'm sure some of this is wrong, so as of now it serves as a hack fix.
if (m_env.PRIM.TME && !m_context->TEX1.MMAG && !(m_context->TEX1.MMIN & 1) && GSConfig.PreRoundSprites)
{
if (m_env.PRIM.FST) // UV's
{
for (int i = 0; i < m_index.tail; i++)
{
GSVertex* v = &m_vertex.buff[m_index.buff[i]];

if ((v->U & 0xF) < 0x8 && v->U >= 0x10)
{
v->U = (v->U - 0x10);
}
if ((v->V & 0xF) < 0x8 && v->V >= 0x10)
{
v->V = (v->V - 0x10);
}
v->U = (v->U & ~0xF);
v->V = (v->V & ~0xF);
}
}
else
{
for (int i = 0; i < m_vertex.tail; i++)
{
GSVertex* v = &m_vertex.buff[i];

int x = (int)(static_cast<float>(1 << m_context->TEX0.TW) * (v->ST.S / v->RGBAQ.Q) * 16.0f);
int y = (int)(static_cast<float>(1 << m_context->TEX0.TH) * (v->ST.T / v->RGBAQ.Q) * 16.0f);

if ((x & 0xF) < 0x8)
{
x = (x - 0x10);
}
if ((y & 0xF) < 0x8)
{
y = (y - 0x10);
}
x = (x & ~0xF);
y = (y & ~0xF);

v->ST.S = ((static_cast<float>(x) / 16.0f) * v->RGBAQ.Q) / static_cast<float>(1 << m_context->TEX0.TW);
v->ST.T = ((static_cast<float>(y) / 16.0f) * v->RGBAQ.Q) / static_cast<float>(1 << m_context->TEX0.TH);
}
}
}

// If the PSM format of Z is invalid, but it is masked (no write) and ZTST is set to ALWAYS pass (no test, just allow)
// we can ignore the Z format, since it won't be used in the draw (Star Ocean 3 transitions)
const bool ignoreZ = m_context->ZBUF.ZMSK && m_context->TEST.ZTST == 1;
Expand Down Expand Up @@ -1869,7 +1921,6 @@ void GSState::FlushPrim()
if (unused > 0)
{
memcpy(m_vertex.buff, buff, sizeof(GSVertex) * unused);

m_vertex.tail = unused;
m_vertex.next = next > head ? next - head : 0;
}
Expand Down Expand Up @@ -3030,10 +3081,11 @@ __forceinline void GSState::VertexKick(u32 skip)
GSVector4i v1(m_v.m[1]);

GSVector4i* RESTRICT tailptr = (GSVector4i*)&m_vertex.buff[tail];

tailptr[0] = v0;
tailptr[1] = v1;


const GSVector4i xy = v1.xxxx().u16to32().sub32(m_ofxy);

GSVector4i::storel(&m_vertex.xy[xy_tail & 3], xy.blend16<0xf0>(xy.sra32(4)).ps32());
Expand Down
4 changes: 4 additions & 0 deletions pcsx2/GS/Window/GSSetting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ const char* dialog_message(int ID, bool* updateText)
return cvtString("Enable: Removes the offset for interlacing when upscaling.\n"
"Can reduce blurring in some games, where the opposite is true most of the time.\n"
"Used for ICO to reduce blur.");
case IDC_PREROUND_SPRITES:
return cvtString("Enable: Attempts to pre-round sprite texel coordinates.\n"
"Can improve effects in some games, such as the water in Beyond Good and Evil\n"
"and the light bleed in Manhunt");
case IDC_ACCURATE_DATE:
return cvtString("Implement a more accurate algorithm to compute GS destination alpha testing.\n"
"It improves shadow and transparency rendering.\n\n"
Expand Down
1 change: 1 addition & 0 deletions pcsx2/GS/Window/GSSetting.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ enum
IDC_PCRTC_OVERSCAN,
IDC_PCRTC_ANTIBLUR,
IDC_DISABLE_INTERLACE_OFFSETS,
IDC_PREROUND_SPRITES,
// Hardware Renderer
IDC_PRELOAD_TEXTURES,
IDC_ACCURATE_DATE,
Expand Down
1 change: 1 addition & 0 deletions pcsx2/GS/Window/GSwxDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ RendererTab::RendererTab(wxWindow* parent)
m_ui.addCheckBox(pcrtc_checks_box, "Show Overscan", "pcrtc_overscan", IDC_PCRTC_OVERSCAN);
m_ui.addCheckBox(pcrtc_checks_box, "Disable Interlace Offset", "disable_interlace_offset", IDC_DISABLE_INTERLACE_OFFSETS);
m_ui.addCheckBox(pcrtc_checks_box, "Anti-Blur", "pcrtc_antiblur", IDC_PCRTC_ANTIBLUR);
m_ui.addCheckBox(pcrtc_checks_box, "Pre-Round Sprites", "preround_sprites", IDC_PREROUND_SPRITES);
general_box->Add(pcrtc_checks_box, wxSizerFlags().Center());

tab_box->Add(hardware_box.outer, wxSizerFlags().Expand());
Expand Down
5 changes: 5 additions & 0 deletions pcsx2/GameDatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ static const char* s_gs_hw_fix_names[] = {
"mergeSprite",
"wildArmsHack",
"pointListPalette",
"preRoundSprites",
"mipmap",
"trilinearFiltering",
"skipDrawStart",
Expand Down Expand Up @@ -319,6 +320,7 @@ bool GameDatabaseSchema::isUserHackHWFix(GSHWFixId id)
case GSHWFixId::TexturePreloading:
case GSHWFixId::ConservativeFramebuffer:
case GSHWFixId::PointListPalette:
case GSHWFixId::PreRoundSprites:
return false;

#ifdef PCSX2_CORE
Expand Down Expand Up @@ -504,6 +506,9 @@ u32 GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions&
case GSHWFixId::PointListPalette:
config.PointListPalette = (value > 0);
break;
case GSHWFixId::PreRoundSprites:
config.PreRoundSprites = (value > 0);
break;

case GSHWFixId::Mipmap:
{
Expand Down
1 change: 1 addition & 0 deletions pcsx2/GameDatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ namespace GameDatabaseSchema
MergeSprite,
WildArmsHack,
PointListPalette,
PreRoundSprites,

// integer settings
Mipmap,
Expand Down
2 changes: 2 additions & 0 deletions pcsx2/Pcsx2Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ Pcsx2Config::GSOptions::GSOptions()
Mipmap = true;
AA1 = true;
PointListPalette = false;
PreRoundSprites = false;

ManualUserHacks = false;
UserHacks_AlignSpriteX = false;
Expand Down Expand Up @@ -533,6 +534,7 @@ void Pcsx2Config::GSOptions::ReloadIniSettings()
GSSettingBool(OsdShowResolution);
GSSettingBool(OsdShowGSStats);
GSSettingBool(OsdShowIndicators);
GSSettingBoolEx(PreRoundSprites, "preround_sprites");

GSSettingBool(HWDisableReadbacks);
GSSettingBoolEx(AccurateDATE, "accurate_date");
Expand Down

0 comments on commit cf5a3d6

Please sign in to comment.