Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: GS: Add Pre-Round Sprite hack #6553

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pcsx2-qt/Settings/GraphicsSettingsWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.screenshotFormat, "EmuCore/GS", "ScreenshotFormat", static_cast<int>(GSScreenshotFormat::PNG));
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.screenshotQuality, "EmuCore/GS", "ScreenshotQuality", 50);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.PreRoundSprites, "EmuCore/GS", "preround_sprites", false);
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.stretchY, "EmuCore/GS", "StretchY", 100.0f);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cropLeft, "EmuCore/GS", "CropLeft", 0);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cropTop, "EmuCore/GS", "CropTop", 0);
Expand Down
10 changes: 10 additions & 0 deletions pcsx2-qt/Settings/GraphicsSettingsWidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,16 @@
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="PreRoundSprites">
<property name="toolTip">
<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>Pre-Round Sprites</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
Expand Down
1 change: 1 addition & 0 deletions pcsx2/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,7 @@ struct Pcsx2Config
PreloadFrameWithGSData : 1,
Mipmap : 1,
HWMipmap : 1,
PreRoundSprites : 1,
ManualUserHacks : 1,
UserHacks_AlignSpriteX : 1,
UserHacks_CPUFBConversion : 1,
Expand Down
93 changes: 90 additions & 3 deletions pcsx2/GS/GSState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1683,7 +1683,96 @@ void GSState::FlushPrim()
// Sometimes hardware doesn't get affected, likely due to the difference in how GPU's handle textures (Persona minimap).
if (PRIM->TME && (GSUtil::GetPrimClass(PRIM->PRIM) == GS_PRIM_CLASS::GS_SPRITE_CLASS || m_vt.m_eq.z))
{
if (!PRIM->FST) // STQ's
if (PRIM->FST && GSConfig.PreRoundSprites) // UV's
{
// UV's on sprites only alter the final UV, I believe the problem is we're drawing too much (drawing stops earlier than we do)
// But this fixes Beyond Good adn Evil water and Dark Cloud 2's UI
if (GSUtil::GetPrimClass(PRIM->PRIM) == GS_PRIM_CLASS::GS_SPRITE_CLASS)
{
for (u32 i = 0; i < m_index.tail; i += 2)
{
GSVertex* v1 = &m_vertex.buff[m_index.buff[i]];
GSVertex* v2 = &m_vertex.buff[m_index.buff[i + 1]];

GSVertex* vu1;
GSVertex* vu2;
GSVertex* vv1;
GSVertex* vv2;
if (v1->U > v2->U)
{
vu2 = v1;
vu1 = v2;
}
else
{
vu2 = v2;
vu1 = v1;
}

if (v1->V > v2->V)
{
vv2 = v1;
vv1 = v2;
}
else
{
vv2 = v2;
vv1 = v1;
}

GSVector2 pos_range(vu2->XYZ.X - vu1->XYZ.X, vv2->XYZ.Y - vv1->XYZ.Y);
const GSVector2 uv_range(vu2->U - vu1->U, vv2->V - vv1->V);
if (pos_range.x == 0)
pos_range.x = 1;
if (pos_range.y == 0)
pos_range.y = 1;
const GSVector2 grad(uv_range / pos_range);
bool isclamp_w = m_context->CLAMP.WMS > 0 && m_context->CLAMP.WMS < 3;
bool isclamp_h = m_context->CLAMP.WMT > 0 && m_context->CLAMP.WMT < 3;
int max_w = (m_context->CLAMP.WMS == 2) ? m_context->CLAMP.MAXU : ((1 << m_context->TEX0.TW) - 1);
int max_h = (m_context->CLAMP.WMT == 2) ? m_context->CLAMP.MAXV : ((1 << m_context->TEX0.TH) - 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and the 3 above as well.

int width = vu2->U >> 4;
int height = vv2->V >> 4;

if (m_context->CLAMP.WMS == 3)
width = (width & m_context->CLAMP.MINU) | m_context->CLAMP.MAXU;

if (m_context->CLAMP.WMT == 3)
height = (height & m_context->CLAMP.MINV) | m_context->CLAMP.MAXV;

if ((isclamp_w && width <= max_w && grad.x != 1.0f) || !isclamp_w)
{
if (vu2->U >= 0x1 && (!(vu2->U & 0xf) || grad.x <= 1.0f))
{
vu2->U = (vu2->U - 1);
/*if (!isclamp_w && ((vu2->XYZ.X - m_context->XYOFFSET.OFX) >> 4) < m_context->scissor.in.z)
vu2->XYZ.X -= 1;*/
}
}
else
vu2->U &= ~0xf;

// Dark Cloud 2 tries to address wider than the TBW when in CLAMP mode (maybe some weird behaviour in HW?)
if ((vu2->U >> 4) > (int)(m_context->TEX0.TBW * 64) && isclamp_w && (vu2->U >> 4) - 8 <= (int)(m_context->TEX0.TBW * 64))
{
vu2->U = (m_context->TEX0.TBW * 64) << 4;
}

if ((isclamp_h && height <= max_h && grad.y != 1.0f) || !isclamp_h)
{
if (vv2->V >= 0x1 && (!(vv2->V & 0xf) || grad.y <= 1.0f))
{
vv2->V = (vv2->V - 1);
/*if (!isclamp_h && ((vv2->XYZ.Y - m_context->XYOFFSET.OFY) >> 4) < m_context->scissor.in.w)
vv2->XYZ.Y -= 1;*/
}
}
else
vv2->V &= ~0xf;
}
}
}
else if (!PRIM->FST) // STQ's
{
const bool is_sprite = GSUtil::GetPrimClass(PRIM->PRIM) == GS_PRIM_CLASS::GS_SPRITE_CLASS;
// ST's have the lowest 9 bits (or greater depending on exponent difference) rounding down (from hardware tests).
Expand Down Expand Up @@ -1736,7 +1825,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 @@ -3486,7 +3574,6 @@ __forceinline void GSState::VertexKick(u32 skip)
const GSVector4i new_v1(m_v.m[1]);

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

tailptr[0] = new_v0;
tailptr[1] = new_v1;

Expand Down
6 changes: 6 additions & 0 deletions pcsx2/GameDatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ static const char* s_gs_hw_fix_names[] = {
"estimateTextureRegion",
"PCRTCOffsets",
"PCRTCOverscan",
"preRoundSprites",
"trilinearFiltering",
"skipDrawStart",
"skipDrawEnd",
Expand Down Expand Up @@ -423,6 +424,7 @@ bool GameDatabaseSchema::isUserHackHWFix(GSHWFixId id)
case GSHWFixId::Deinterlace:
case GSHWFixId::Mipmap:
case GSHWFixId::TexturePreloading:
case GSHWFixId::PreRoundSprites:
case GSHWFixId::TrilinearFiltering:
case GSHWFixId::MinimumBlendingLevel:
case GSHWFixId::MaximumBlendingLevel:
Expand Down Expand Up @@ -779,6 +781,10 @@ void GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions&
config.PCRTCOverscan = (value > 0);
break;

case GSHWFixId::PreRoundSprites:
config.PreRoundSprites = (value > 0);
break;

case GSHWFixId::Mipmap:
config.HWMipmap = (value > 0);
break;
Expand Down
1 change: 1 addition & 0 deletions pcsx2/GameDatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ namespace GameDatabaseSchema
EstimateTextureRegion,
PCRTCOffsets,
PCRTCOverscan,
PreRoundSprites,

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

ManualUserHacks = false;
UserHacks_AlignSpriteX = false;
Expand Down Expand Up @@ -938,6 +939,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitBool(OsdShowVideoCapture);
SettingsWrapBitBool(OsdShowInputRec);

SettingsWrapBitBoolEx(PreRoundSprites, "preround_sprites");
SettingsWrapBitBool(HWSpinGPUForReadbacks);
SettingsWrapBitBool(HWSpinCPUForReadbacks);
SettingsWrapBitBoolEx(GPUPaletteConversion, "paltex");
Expand Down
Loading