GS/HW: Correct some scaling behaviour

This commit is contained in:
refractionpcsx2 2024-06-07 21:38:15 +01:00
parent 1d46ec2059
commit 2fc6357ac4
3 changed files with 37 additions and 29 deletions

View File

@ -2674,7 +2674,7 @@ void GSRendererHW::Draw()
GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16 && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16) || GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16 && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16) ||
IsPossibleChannelShuffle()); IsPossibleChannelShuffle());
rt = g_texture_cache->LookupTarget(FRAME_TEX0, t_size, target_scale, GSTextureCache::RenderTarget, true, rt = g_texture_cache->LookupTarget(FRAME_TEX0, t_size, target_scale, GSTextureCache::RenderTarget, true,
fm, false, force_preload, preserve_rt_rgb, preserve_rt_alpha, unclamped_draw_rect, possible_shuffle, is_possible_mem_clear && FRAME_TEX0.TBP0 != m_cached_ctx.ZBUF.Block()); fm, false, force_preload, preserve_rt_rgb, preserve_rt_alpha, unclamped_draw_rect, possible_shuffle, is_possible_mem_clear && FRAME_TEX0.TBP0 != m_cached_ctx.ZBUF.Block(), scale_draw < 0);
// Draw skipped because it was a clear and there was no target. // Draw skipped because it was a clear and there was no target.
if (!rt) if (!rt)
@ -2696,7 +2696,7 @@ void GSRendererHW::Draw()
return; return;
} }
rt = g_texture_cache->CreateTarget(FRAME_TEX0, t_size, GetValidSize(src), target_scale, GSTextureCache::RenderTarget, true, rt = g_texture_cache->CreateTarget(FRAME_TEX0, t_size, GetValidSize(src), (scale_draw < 0) ? src->m_from_target->GetScale() : target_scale, GSTextureCache::RenderTarget, true,
fm, false, force_preload, preserve_rt_color, m_r, src); fm, false, force_preload, preserve_rt_color, m_r, src);
if (!rt) [[unlikely]] if (!rt) [[unlikely]]
{ {
@ -2705,18 +2705,16 @@ void GSRendererHW::Draw()
return; return;
} }
} }
else
{
if (src && src->m_from_target && src->m_target_direct && src->m_from_target == rt)
{
src->m_texture = rt->m_texture;
src->m_scale = rt->m_scale;
src->m_unscaled_size = rt->m_unscaled_size;
}
target_scale = rt->GetScale(); if (src && src->m_from_target && src->m_target_direct && src->m_from_target == rt)
{
src->m_texture = rt->m_texture;
src->m_scale = rt->GetScale();
src->m_unscaled_size = rt->m_unscaled_size;
} }
target_scale = rt->GetScale();
// The target might have previously been a C32 format with valid alpha. If we're switching to C24, we need to preserve it. // The target might have previously been a C32 format with valid alpha. If we're switching to C24, we need to preserve it.
preserve_rt_alpha |= (GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].trbpp == 24 && rt->HasValidAlpha()); preserve_rt_alpha |= (GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].trbpp == 24 && rt->HasValidAlpha());
preserve_rt_color = preserve_rt_rgb || preserve_rt_alpha; preserve_rt_color = preserve_rt_rgb || preserve_rt_alpha;
@ -4760,6 +4758,10 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
float scale = tex->GetScale(); float scale = tex->GetScale();
HandleTextureHazards(rt, ds, tex, tmm, source_region, target_region, unscaled_size, scale, src_copy); HandleTextureHazards(rt, ds, tex, tmm, source_region, target_region, unscaled_size, scale, src_copy);
// This is used for reading depth sources, so we should go off the source scale.
float scale_factor = scale;
m_conf.cb_ps.ScaleFactor = GSVector4(scale_factor * (1.0f / 16.0f), 1.0f / scale_factor, scale_factor, 0.0f);
if ((m_conf.ps.tex_is_fb && rt->m_rt_alpha_scale) || (tex->m_target && tex->m_from_target && tex->m_target_direct && tex->m_from_target->m_rt_alpha_scale)) if ((m_conf.ps.tex_is_fb && rt->m_rt_alpha_scale) || (tex->m_target && tex->m_from_target && tex->m_target_direct && tex->m_from_target->m_rt_alpha_scale))
m_conf.ps.rta_source_correction = 1; m_conf.ps.rta_source_correction = 1;
@ -5437,9 +5439,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
ResetStates(); ResetStates();
const float scale_factor = rt ? rt->GetScale() : ds->GetScale();
m_conf.cb_vs.texture_offset = {}; m_conf.cb_vs.texture_offset = {};
m_conf.cb_ps.ScaleFactor = GSVector4(scale_factor * (1.0f / 16.0f), 1.0f / scale_factor, scale_factor, 0.0f);
m_conf.ps.scanmsk = env.SCANMSK.MSK; m_conf.ps.scanmsk = env.SCANMSK.MSK;
m_conf.rt = rt ? rt->m_texture : nullptr; m_conf.rt = rt ? rt->m_texture : nullptr;
m_conf.ds = ds ? ds->m_texture : nullptr; m_conf.ds = ds ? ds->m_texture : nullptr;
@ -6058,6 +6058,9 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
} }
else else
{ {
const float scale_factor = rt ? rt->GetScale() : ds->GetScale();
m_conf.cb_ps.ScaleFactor = GSVector4(scale_factor * (1.0f / 16.0f), 1.0f / scale_factor, scale_factor, 0.0f);
m_conf.ps.tfx = 4; m_conf.ps.tfx = 4;
} }
@ -7206,28 +7209,28 @@ bool GSRendererHW::TextureCoversWithoutGapsNotEqual()
int GSRendererHW::IsScalingDraw(GSTextureCache::Source* src, bool no_gaps) int GSRendererHW::IsScalingDraw(GSTextureCache::Source* src, bool no_gaps)
{ {
// Try to detect if a game is downscaling/upscaling the image in order to do post processing/bloom effects.
const GSVector2i draw_size = GSVector2i(m_vt.m_max.p.x - m_vt.m_min.p.x, m_vt.m_max.p.y - m_vt.m_min.p.y);
const GSVector2i tex_size = GSVector2i(m_vt.m_max.t.x - m_vt.m_min.t.x, m_vt.m_max.t.y - m_vt.m_min.t.y);
const bool is_downscale = (tex_size.x / 2.0f) >= draw_size.x && (tex_size.y / 2.0f) >= draw_size.y;
if (is_downscale && draw_size.x >= PCRTCDisplays.GetResolution().x)
return 0;
if (GSConfig.UserHacks_NativeScaling == GSNativeScaling::Off) if (GSConfig.UserHacks_NativeScaling == GSNativeScaling::Off)
return 0; return 0;
const GSVector2i draw_size = GSVector2i(m_vt.m_max.p.x - m_vt.m_min.p.x, m_vt.m_max.p.y - m_vt.m_min.p.y);
const GSVector2i tex_size = GSVector2i(m_vt.m_max.t.x - m_vt.m_min.t.x, m_vt.m_max.t.y - m_vt.m_min.t.y);
// Check if we're already downscaled and drawing in current size, try not to rescale it. // Check if we're already downscaled and drawing in current size, try not to rescale it.
if (src && src->m_from_target && src->m_from_target->m_downscaled && std::abs(draw_size.x - tex_size.x) <= 1 && std::abs(draw_size.y - tex_size.y) <= 1) if (src && src->m_from_target && (std::abs(draw_size.x - tex_size.x) <= 1 && std::abs(draw_size.y - tex_size.y) <= 1))
return 1; return -1;
// Try to detect if a game is downscaling/upscaling the image in order to do post processing/bloom effects.
const bool is_downscale = (tex_size.x / 2.0f) >= (draw_size.x - 1) && (tex_size.y / 2.0f) >= (draw_size.y - 1);
if (is_downscale && draw_size.x >= PCRTCDisplays.GetResolution().x)
return 0;
const bool is_upscale = (draw_size.x / 2.0f) >= (tex_size.x - 1) && (draw_size.y / 2.0f) >= (tex_size.y - 1);
const bool is_upscale = (draw_size.x / 2.0f) >= tex_size.x && (draw_size.y / 2.0f) >= tex_size.y;
const bool target_scale = is_downscale ? true : false;
// DMC does a blit in strips with the scissor to keep it inside page boundaries, so that's not technically full coverage // DMC does a blit in strips with the scissor to keep it inside page boundaries, so that's not technically full coverage
// but good enough for what we want. // but good enough for what we want.
const bool no_gaps_or_single_sprite = (no_gaps || (m_vt.m_primclass == GS_SPRITE_CLASS && SpriteDrawWithoutGaps())); const bool no_gaps_or_single_sprite = (no_gaps || (m_vt.m_primclass == GS_SPRITE_CLASS && SpriteDrawWithoutGaps()));
if (no_gaps_or_single_sprite && m_vt.m_primclass >= GS_TRIANGLE_CLASS && m_context->TEX1.MMAG == 1 && src && src->m_from_target && if (no_gaps_or_single_sprite && m_vt.m_primclass >= GS_TRIANGLE_CLASS && m_context->TEX1.MMAG == 1 && src && src->m_from_target &&
GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp > 8 && m_cached_ctx.FRAME.Block() != m_cached_ctx.TEX0.TBP0 && !IsMipMapDraw() && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp > 8 && m_cached_ctx.FRAME.Block() != m_cached_ctx.TEX0.TBP0 && !IsMipMapDraw() &&
((is_upscale && !IsDiscardingDstColor()) || (IsDiscardingDstColor() && is_downscale))) ((is_upscale && !IsDiscardingDstColor()) || (((PRIM->ABE && m_context->ALPHA.C == 2 && m_context->ALPHA.FIX == 255) || IsDiscardingDstColor()) && is_downscale)))
{ {
GL_INS("%s draw detected - from %dx%d to %dx%d", is_downscale ? "Downscale" : "Upscale", tex_size.x, tex_size.y, draw_size.x, draw_size.y); GL_INS("%s draw detected - from %dx%d to %dx%d", is_downscale ? "Downscale" : "Upscale", tex_size.x, tex_size.y, draw_size.x, draw_size.y);
return is_upscale ? 2 : 1; return is_upscale ? 2 : 1;

View File

@ -987,6 +987,7 @@ GSTextureCache::Source* GSTextureCache::LookupDepthSource(const bool is_depth, c
src->m_unscaled_size = dst->m_unscaled_size; src->m_unscaled_size = dst->m_unscaled_size;
src->m_shared_texture = true; src->m_shared_texture = true;
src->m_target = true; // So renderer can check if a conversion is required src->m_target = true; // So renderer can check if a conversion is required
src->m_target_direct = true;
src->m_from_target = dst; // avoid complex condition on the renderer src->m_from_target = dst; // avoid complex condition on the renderer
src->m_from_target_TEX0 = dst->m_TEX0; src->m_from_target_TEX0 = dst->m_TEX0;
src->m_32_bits_fmt = dst->m_32_bits_fmt; src->m_32_bits_fmt = dst->m_32_bits_fmt;
@ -1746,6 +1747,8 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
if (src->m_target && src->m_from_target) if (src->m_target && src->m_from_target)
{ {
src->m_valid_alpha_minmax = true; src->m_valid_alpha_minmax = true;
if (src->m_target_direct)
src->m_scale = src->m_from_target->GetScale();
if ((src->m_TEX0.PSM & 0xf) == PSMCT24) if ((src->m_TEX0.PSM & 0xf) == PSMCT24)
{ {
@ -1797,7 +1800,7 @@ GSVector2i GSTextureCache::ScaleRenderTargetSize(const GSVector2i& sz, float sca
} }
GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type, GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type,
bool used, u32 fbmask, bool is_frame, bool preload, bool preserve_rgb, bool preserve_alpha, const GSVector4i draw_rect, bool is_shuffle, bool possible_clear) bool used, u32 fbmask, bool is_frame, bool preload, bool preserve_rgb, bool preserve_alpha, const GSVector4i draw_rect, bool is_shuffle, bool possible_clear, bool preserve_scale)
{ {
const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM]; const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM];
const u32 bp = TEX0.TBP0; const u32 bp = TEX0.TBP0;
@ -1994,7 +1997,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
dst->m_TEX0.TBP0, dst->m_TEX0.TBW, psm_str(dst->m_TEX0.PSM)); dst->m_TEX0.TBP0, dst->m_TEX0.TBW, psm_str(dst->m_TEX0.PSM));
} }
if (dst->m_scale != scale) if (dst->m_scale != scale && !preserve_scale)
{ {
calcRescale(dst); calcRescale(dst);
GSTexture* tex = type == RenderTarget ? g_gs_device->CreateRenderTarget(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::Color, clear) : GSTexture* tex = type == RenderTarget ? g_gs_device->CreateRenderTarget(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::Color, clear) :
@ -2017,6 +2020,8 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
dst->m_unscaled_size = new_size; dst->m_unscaled_size = new_size;
dst->m_downscaled = scale == 1.0f; dst->m_downscaled = scale == 1.0f;
} }
else if (dst->m_scale != scale)
scale = dst->m_scale;
// If our RGB was invalidated, we need to pull it from depth. // If our RGB was invalidated, we need to pull it from depth.
// Terminator 3 will reuse our dst_matched target with the RGB masked, then later use the full ARGB area, so we need to update the depth. // Terminator 3 will reuse our dst_matched target with the RGB masked, then later use the full ARGB area, so we need to update the depth.

View File

@ -490,8 +490,8 @@ public:
Target* FindTargetOverlap(Target* target, int type, int psm); Target* FindTargetOverlap(Target* target, int type, int psm);
Target* LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type, bool used = true, u32 fbmask = 0, Target* LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type, bool used = true, u32 fbmask = 0,
bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_rgb = true, bool preserve_alpha = true, bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_rgb = true, bool preserve_alpha = true,
const GSVector4i draw_rc = GSVector4i::zero(), bool is_shuffle = false, bool possible_clear = false); const GSVector4i draw_rc = GSVector4i::zero(), bool is_shuffle = false, bool possible_clear = false, bool preserve_scale = false);
Target* CreateTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size,float scale, int type, bool used = true, u32 fbmask = 0, Target* CreateTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size,float scale, int type, bool used = true, u32 fbmask = 0,
bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_target = true, bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_target = true,
const GSVector4i draw_rc = GSVector4i::zero(), GSTextureCache::Source* src = nullptr); const GSVector4i draw_rc = GSVector4i::zero(), GSTextureCache::Source* src = nullptr);