mirror of https://github.com/PCSX2/pcsx2.git
GS/HW: Add 'Align To Native' HPO mode
This commit is contained in:
parent
e2dcabcbea
commit
5338a4f17c
|
@ -1104,6 +1104,11 @@
|
|||
<string>Special (Texture - Aggressive)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Align To Native</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
|
|
|
@ -377,6 +377,16 @@ enum class GSBilinearDirtyMode : u8
|
|||
MaxCount
|
||||
};
|
||||
|
||||
enum class GSHalfPixelOffset : u8
|
||||
{
|
||||
Off,
|
||||
Normal,
|
||||
Special,
|
||||
SpecialAggressive,
|
||||
Native,
|
||||
MaxCount
|
||||
};
|
||||
|
||||
// Template function for casting enumerations to their underlying type
|
||||
template <typename Enumeration>
|
||||
typename std::underlying_type<Enumeration>::type enum_cast(Enumeration E)
|
||||
|
@ -761,7 +771,7 @@ struct Pcsx2Config
|
|||
int SkipDrawEnd = 0;
|
||||
|
||||
GSHWAutoFlushLevel UserHacks_AutoFlush = GSHWAutoFlushLevel::Disabled;
|
||||
s8 UserHacks_HalfPixelOffset = 0;
|
||||
GSHalfPixelOffset UserHacks_HalfPixelOffset = GSHalfPixelOffset::Off;
|
||||
s8 UserHacks_RoundSprite = 0;
|
||||
s32 UserHacks_TCOffsetX = 0;
|
||||
s32 UserHacks_TCOffsetY = 0;
|
||||
|
|
|
@ -270,7 +270,7 @@ float GSRenderer::GetModXYOffset()
|
|||
{
|
||||
float mod_xy = 0.0f;
|
||||
|
||||
if (GSConfig.UserHacks_HalfPixelOffset == 1)
|
||||
if (GSConfig.UserHacks_HalfPixelOffset == GSHalfPixelOffset::Normal)
|
||||
{
|
||||
mod_xy = GetUpscaleMultiplier();
|
||||
switch (static_cast<int>(std::round(mod_xy)))
|
||||
|
|
|
@ -593,8 +593,12 @@ void GSRendererHW::ConvertSpriteTextureShuffle(bool& write_ba, bool& read_ba, GS
|
|||
|
||||
GSVector4 GSRendererHW::RealignTargetTextureCoordinate(const GSTextureCache::Source* tex)
|
||||
{
|
||||
if (GSConfig.UserHacks_HalfPixelOffset <= 1 || GetUpscaleMultiplier() == 1.0f)
|
||||
if (GSConfig.UserHacks_HalfPixelOffset <= GSHalfPixelOffset::Normal ||
|
||||
GSConfig.UserHacks_HalfPixelOffset == GSHalfPixelOffset::Native ||
|
||||
GetUpscaleMultiplier() == 1.0f)
|
||||
{
|
||||
return GSVector4(0.0f);
|
||||
}
|
||||
|
||||
const GSVertex* v = &m_vertex.buff[0];
|
||||
const float scale = tex->GetScale();
|
||||
|
@ -607,7 +611,7 @@ GSVector4 GSRendererHW::RealignTargetTextureCoordinate(const GSTextureCache::Sou
|
|||
|
||||
if (PRIM->FST)
|
||||
{
|
||||
if (GSConfig.UserHacks_HalfPixelOffset == 3)
|
||||
if (GSConfig.UserHacks_HalfPixelOffset == GSHalfPixelOffset::SpecialAggressive)
|
||||
{
|
||||
if (!linear && t_position == 8)
|
||||
{
|
||||
|
@ -5154,30 +5158,43 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
|||
m_conf.vs.fst = PRIM->FST;
|
||||
|
||||
// FIXME D3D11 and GL support half pixel center. Code could be easier!!!
|
||||
const GSVector2i rtsize = m_conf.ds ? m_conf.ds->GetSize() : m_conf.rt->GetSize();
|
||||
const float rtscale = (ds ? ds->GetScale() : rt->GetScale());
|
||||
const float sx = 2.0f * rtscale / (rtsize.x << 4);
|
||||
const float sy = 2.0f * rtscale / (rtsize.y << 4);
|
||||
const float ox = static_cast<float>(static_cast<int>(m_context->XYOFFSET.OFX));
|
||||
const float oy = static_cast<float>(static_cast<int>(m_context->XYOFFSET.OFY));
|
||||
float ox2 = -1.0f / rtsize.x;
|
||||
float oy2 = -1.0f / rtsize.y;
|
||||
float mod_xy = 0.0f;
|
||||
//This hack subtracts around half a pixel from OFX and OFY.
|
||||
//
|
||||
//The resulting shifted output aligns better with common blending / corona / blurring effects,
|
||||
//but introduces a few bad pixels on the edges.
|
||||
if (!rt)
|
||||
const GSTextureCache::Target* rt_or_ds = rt ? rt : ds;
|
||||
const GSVector2i rtsize = rt_or_ds->GetTexture()->GetSize();
|
||||
const float rtscale = rt_or_ds->GetScale();
|
||||
float sx, sy, ox, oy, ox2, oy2;
|
||||
if (GSConfig.UserHacks_HalfPixelOffset != GSHalfPixelOffset::Native)
|
||||
{
|
||||
mod_xy = GetModXYOffset();
|
||||
sx = 2.0f * rtscale / (rtsize.x << 4);
|
||||
sy = 2.0f * rtscale / (rtsize.y << 4);
|
||||
ox = static_cast<float>(static_cast<int>(m_context->XYOFFSET.OFX));
|
||||
oy = static_cast<float>(static_cast<int>(m_context->XYOFFSET.OFY));
|
||||
ox2 = -1.0f / rtsize.x;
|
||||
oy2 = -1.0f / rtsize.y;
|
||||
float mod_xy = 0.0f;
|
||||
//This hack subtracts around half a pixel from OFX and OFY.
|
||||
//
|
||||
//The resulting shifted output aligns better with common blending / corona / blurring effects,
|
||||
//but introduces a few bad pixels on the edges.
|
||||
if (!rt)
|
||||
mod_xy = GetModXYOffset();
|
||||
else
|
||||
mod_xy = rt->OffsetHack_modxy;
|
||||
|
||||
if (mod_xy > 1.0f)
|
||||
{
|
||||
ox2 *= mod_xy;
|
||||
oy2 *= mod_xy;
|
||||
}
|
||||
}
|
||||
else
|
||||
mod_xy = rt->OffsetHack_modxy;
|
||||
|
||||
if (mod_xy > 1.0f)
|
||||
{
|
||||
ox2 *= mod_xy;
|
||||
oy2 *= mod_xy;
|
||||
// Align coordinates to native resolution framebuffer, hope for the best.
|
||||
sx = 2.0f / (rt_or_ds->GetUnscaledWidth() << 4);
|
||||
sy = 2.0f / (rt_or_ds->GetUnscaledHeight() << 4);
|
||||
ox = static_cast<float>(static_cast<int>(m_context->XYOFFSET.OFX));
|
||||
oy = static_cast<float>(static_cast<int>(m_context->XYOFFSET.OFY));
|
||||
ox2 = -1.0f / rt_or_ds->GetUnscaledWidth();
|
||||
oy2 = -1.0f / rt_or_ds->GetUnscaledHeight();
|
||||
}
|
||||
|
||||
m_conf.cb_vs.vertex_scale = GSVector2(sx, sy);
|
||||
|
|
|
@ -606,7 +606,7 @@ bool GameDatabaseSchema::GameEntry::configMatchesHWFix(const Pcsx2Config::GSOpti
|
|||
return (config.SkipDrawEnd == value);
|
||||
|
||||
case GSHWFixId::HalfPixelOffset:
|
||||
return (config.UpscaleMultiplier <= 1.0f || config.UserHacks_HalfPixelOffset == value);
|
||||
return (config.UpscaleMultiplier <= 1.0f || config.UserHacks_HalfPixelOffset == static_cast<GSHalfPixelOffset>(value));
|
||||
|
||||
case GSHWFixId::RoundSprite:
|
||||
return (config.UpscaleMultiplier <= 1.0f || config.UserHacks_RoundSprite == value);
|
||||
|
@ -780,8 +780,11 @@ void GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions&
|
|||
break;
|
||||
|
||||
case GSHWFixId::HalfPixelOffset:
|
||||
config.UserHacks_HalfPixelOffset = value;
|
||||
break;
|
||||
{
|
||||
if (value >= 0 && value < static_cast<int>(GSHalfPixelOffset::MaxCount))
|
||||
config.UserHacks_HalfPixelOffset = static_cast<GSHalfPixelOffset>(value);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSHWFixId::RoundSprite:
|
||||
config.UserHacks_RoundSprite = value;
|
||||
|
|
|
@ -3314,6 +3314,7 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
|||
FSUI_NSTR("Normal (Vertex)"),
|
||||
FSUI_NSTR("Special (Texture)"),
|
||||
FSUI_NSTR("Special (Texture - Aggressive)"),
|
||||
FSUI_NSTR("Align To Native"),
|
||||
};
|
||||
static constexpr const char* s_round_sprite_options[] = {
|
||||
FSUI_NSTR("Off (Default)"),
|
||||
|
@ -7034,6 +7035,7 @@ TRANSLATE_NOOP("FullscreenUI", "Merge Targets");
|
|||
TRANSLATE_NOOP("FullscreenUI", "Normal (Vertex)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Special (Texture)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Special (Texture - Aggressive)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Align To Native");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Half");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Force Bilinear");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Force Nearest");
|
||||
|
|
|
@ -391,8 +391,8 @@ void ImGuiManager::DrawSettingsOverlay()
|
|||
APPEND("AF={} ", EmuConfig.GS.MaxAnisotropy);
|
||||
if (GSConfig.Dithering != 2)
|
||||
APPEND("DI={} ", GSConfig.Dithering);
|
||||
if (GSConfig.UserHacks_HalfPixelOffset > 0)
|
||||
APPEND("HPO={} ", GSConfig.UserHacks_HalfPixelOffset);
|
||||
if (GSConfig.UserHacks_HalfPixelOffset != GSHalfPixelOffset::Off)
|
||||
APPEND("HPO={} ", static_cast<u32>(GSConfig.UserHacks_HalfPixelOffset));
|
||||
if (GSConfig.UserHacks_RoundSprite > 0)
|
||||
APPEND("RS={} ", GSConfig.UserHacks_RoundSprite);
|
||||
if (GSConfig.UserHacks_TCOffsetX != 0 || GSConfig.UserHacks_TCOffsetY != 0)
|
||||
|
|
|
@ -805,7 +805,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
|
|||
GSSettingIntEx(SkipDrawEnd, "UserHacks_SkipDraw_End");
|
||||
SkipDrawEnd = std::max(SkipDrawStart, SkipDrawEnd);
|
||||
|
||||
GSSettingIntEx(UserHacks_HalfPixelOffset, "UserHacks_HalfPixelOffset");
|
||||
GSSettingIntEnumEx(UserHacks_HalfPixelOffset, "UserHacks_HalfPixelOffset");
|
||||
GSSettingIntEx(UserHacks_RoundSprite, "UserHacks_round_sprite_offset");
|
||||
GSSettingIntEx(UserHacks_TCOffsetX, "UserHacks_TCOffsetX");
|
||||
GSSettingIntEx(UserHacks_TCOffsetY, "UserHacks_TCOffsetY");
|
||||
|
@ -872,7 +872,7 @@ void Pcsx2Config::GSOptions::MaskUserHacks()
|
|||
UserHacks_NativePaletteDraw = false;
|
||||
UserHacks_DisableSafeFeatures = false;
|
||||
UserHacks_DisableRenderFixes = false;
|
||||
UserHacks_HalfPixelOffset = 0;
|
||||
UserHacks_HalfPixelOffset = GSHalfPixelOffset::Off;
|
||||
UserHacks_RoundSprite = 0;
|
||||
UserHacks_AutoFlush = GSHWAutoFlushLevel::Disabled;
|
||||
PreloadFrameWithGSData = false;
|
||||
|
@ -903,7 +903,7 @@ void Pcsx2Config::GSOptions::MaskUpscalingHacks()
|
|||
UserHacks_WildHack = false;
|
||||
UserHacks_BilinearHack = GSBilinearDirtyMode::Automatic;
|
||||
UserHacks_NativePaletteDraw = false;
|
||||
UserHacks_HalfPixelOffset = 0;
|
||||
UserHacks_HalfPixelOffset = GSHalfPixelOffset::Off;
|
||||
UserHacks_RoundSprite = 0;
|
||||
UserHacks_TCOffsetX = 0;
|
||||
UserHacks_TCOffsetY = 0;
|
||||
|
|
Loading…
Reference in New Issue