Skip to content

Commit

Permalink
GS/HW: Fixes to texture is target offsets
Browse files Browse the repository at this point in the history
  • Loading branch information
refractionpcsx2 committed Jan 10, 2025
1 parent 76db6f6 commit 030f752
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 64 deletions.
4 changes: 2 additions & 2 deletions bin/resources/shaders/dx11/tfx.fx
Original file line number Diff line number Diff line change
Expand Up @@ -1123,8 +1123,8 @@ PS_OUTPUT ps_main(PS_INPUT input)
{
if (PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
{
C.b = C.r;
C.a = C.g;
C.br = C.rb;
C.ag = C.ga;
}
else if(PS_PROCESS_BA & SHUFFLE_READ)
{
Expand Down
4 changes: 2 additions & 2 deletions bin/resources/shaders/opengl/tfx_fs.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -1086,8 +1086,8 @@ void ps_main()
C.ga = vec2(float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80u)));
#elif PS_SHUFFLE_ACROSS
#if(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
C.b = C.r;
C.a = C.g;
C.br = C.rb;
C.ag = C.ga;
#elif(PS_PROCESS_BA & SHUFFLE_READ)
C.rb = C.bb;
C.ga = C.aa;
Expand Down
4 changes: 2 additions & 2 deletions bin/resources/shaders/vulkan/tfx.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -1350,8 +1350,8 @@ void main()
// Write RB part. Mask will take care of the correct destination
#elif PS_SHUFFLE_ACROSS
#if(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
C.b = C.r;
C.a = C.g;
C.br = C.rb;
C.ag = C.ga;
#elif(PS_PROCESS_BA & SHUFFLE_READ)
C.rb = C.bb;
C.ga = C.aa;
Expand Down
2 changes: 1 addition & 1 deletion pcsx2/GS/GSState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3100,7 +3100,7 @@ __forceinline bool GSState::IsAutoFlushDraw(u32 prim)
{
// Pretty confident here...
GSVertex* buffer = &m_vertex.buff[0];
const bool const_spacing = (buffer[m_index.buff[0]].U - buffer[m_index.buff[0]].XYZ.X) == (m_v.U - m_v.XYZ.X);
const bool const_spacing = std::abs(buffer[m_index.buff[0]].U - buffer[m_index.buff[0]].XYZ.X) == std::abs(m_v.U - m_v.XYZ.X) && std::abs(buffer[m_index.buff[1]].XYZ.X - buffer[m_index.buff[0]].XYZ.X) < 64;

if (const_spacing)
return false;
Expand Down
6 changes: 3 additions & 3 deletions pcsx2/GS/Renderers/HW/GSHwHack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1047,7 +1047,7 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
// compute shadow in RG,
// save result in alpha with a TS,
// Restore RG channel that we previously copied to render shadows.

// Important note: The game downsizes the target to half height, then later expands it back up to full size, that's why PCSX2 doesn't like it, we don't support that behaviour.
const GIFRegTEX0& Texture = RTEX0;

GIFRegTEX0 Frame = {};
Expand All @@ -1058,9 +1058,9 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
if ((!rt) || (!RPRIM->TME) || (GSLocalMemory::m_psm[Texture.PSM].bpp != 16) || (GSLocalMemory::m_psm[Frame.PSM].bpp != 16) || (Texture.TBP0 == Frame.TBP0) || (Frame.TBW != 16 && Texture.TBW != 16))
return true;

GL_INS("OI_SonicUnleashed replace draw by a copy");
GL_INS("OI_SonicUnleashed replace draw by a copy draw %d", r.s_n);

GSTextureCache::Target* src = g_texture_cache->LookupTarget(Texture, GSVector2i(1, 1), r.GetTextureScaleFactor(), GSTextureCache::RenderTarget);
GSTextureCache::Target* src = g_texture_cache->LookupTarget(Texture, GSVector2i(1, 1), r.GetTextureScaleFactor(), GSTextureCache::RenderTarget, true, 0, false, false, true, true, GSVector4i::zero(), true);

if (!src)
return true;
Expand Down
121 changes: 85 additions & 36 deletions pcsx2/GS/Renderers/HW/GSRendererHW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ void GSRendererHW::ConvertSpriteTextureShuffle(u32& process_rg, u32& process_ba,
tex_pos &= 0xFF;
shuffle_across = (((tex_pos + 8) >> 4) ^ ((pos + 8) >> 4)) & 0x8;

const bool full_width = !shuffle_across && (((second_vert.XYZ.X + 9) - first_vert.XYZ.X) >> 4) >= 16 && m_r.width() > 8;
const bool full_width = ((second_vert.XYZ.X - first_vert.XYZ.X) >> 4) >= 16 && m_r.width() > 8 && tex && tex->m_from_target && rt == tex->m_from_target;
process_ba = ((pos > 112 && pos < 136) || full_width) ? SHUFFLE_WRITE : 0;
process_rg = (!process_ba || full_width) ? SHUFFLE_WRITE : 0;
// "same group" means it can read blue and write alpha using C32 tricks
Expand Down Expand Up @@ -733,10 +733,25 @@ void GSRendererHW::ConvertSpriteTextureShuffle(u32& process_rg, u32& process_ba,
m_vt.m_max.p.y = floor(m_vt.m_max.p.y + 1.9f) / 2.0f;
}

m_context->scissor.in.x = m_vt.m_min.p.x;
m_context->scissor.in.z = m_vt.m_max.p.x + 0.9f;
m_context->scissor.in.y = m_vt.m_min.p.y;
m_context->scissor.in.w = m_vt.m_max.p.y + 0.9f;
if (m_context->scissor.in.x & 8)
{
m_context->scissor.in.x &= ~0xf;//m_vt.m_min.p.x;

if (half_right_vert)
m_context->scissor.in.x /= 2;
}
if (m_context->scissor.in.z & 8)
{
m_context->scissor.in.z += 8; //m_vt.m_min.p.x;

if (half_right_vert)
m_context->scissor.in.z /= 2;
}
if (half_bottom_vert)
{
m_context->scissor.in.y /= 2;
m_context->scissor.in.w /= 2;
}

// Only do this is the source is being interpreted as 16bit
if (half_bottom_uv)
Expand Down Expand Up @@ -2570,27 +2585,11 @@ void GSRendererHW::Draw()
bool shuffle_target = false;
if (!no_rt && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp >= 16)
{
if (m_cached_ctx.FRAME.Block() != m_cached_ctx.TEX0.TBP0)
{
// FBW is going to be wrong for channel shuffling into a new target, so take it from the source.
FRAME_TEX0.U64 = 0;
FRAME_TEX0.TBP0 = m_cached_ctx.FRAME.Block();
FRAME_TEX0.TBW = m_cached_ctx.FRAME.FBW;
FRAME_TEX0.PSM = m_cached_ctx.FRAME.PSM;

GSTextureCache::Target* tgt = g_texture_cache->LookupTarget(FRAME_TEX0, GSVector2i(m_vt.m_max.p.x, m_vt.m_max.p.y), GetTextureScaleFactor(), GSTextureCache::RenderTarget, false,
fm, false, false, false, false, GSVector4i::zero(), true);

if (tgt)
shuffle_target = tgt->m_32_bits_fmt;

tgt = nullptr;
}
if (!shuffle_target && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16)
{
const GSVertex* v = &m_vertex.buff[0];

const int first_x = ((v[0].XYZ.X - m_context->XYOFFSET.OFX) + 8) >> 4;
const int first_x = std::abs(static_cast<int>(((v[0].XYZ.X - m_context->XYOFFSET.OFX) + 8))) >> 4;
const int first_u = PRIM->FST ? ((v[0].U + 9) >> 4) : static_cast<int>(((1 << m_cached_ctx.TEX0.TW) * (v[0].ST.S / v[1].RGBAQ.Q)));
const int second_u = PRIM->FST ? ((v[1].U + 9) >> 4) : static_cast<int>(((1 << m_cached_ctx.TEX0.TW) * (v[1].ST.S / v[1].RGBAQ.Q)) + 0.6f);
// offset coordinates swap around RG/BA. (Ace Combat)
Expand All @@ -2604,6 +2603,23 @@ void GSRendererHW::Draw()

shuffle_target = shuffle_coords && (draw_width & 7) == 0 && std::abs(draw_width - read_width) <= 1;
}

if (m_cached_ctx.FRAME.Block() != m_cached_ctx.TEX0.TBP0 || !shuffle_target)
{
// FBW is going to be wrong for channel shuffling into a new target, so take it from the source.
FRAME_TEX0.U64 = 0;
FRAME_TEX0.TBP0 = m_cached_ctx.FRAME.Block();
FRAME_TEX0.TBW = m_cached_ctx.FRAME.FBW;
FRAME_TEX0.PSM = m_cached_ctx.FRAME.PSM;

GSTextureCache::Target* tgt = g_texture_cache->LookupTarget(FRAME_TEX0, GSVector2i(m_vt.m_max.p.x, m_vt.m_max.p.y), GetTextureScaleFactor(), GSTextureCache::RenderTarget, false,
fm, false, false, false, false, GSVector4i::zero(), true);

if (tgt)
shuffle_target = tgt->m_32_bits_fmt;

tgt = nullptr;
}
}

possible_shuffle = !no_rt && (((shuffle_target /*&& GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16*/) /*|| (m_cached_ctx.FRAME.Block() == m_cached_ctx.TEX0.TBP0 && ((m_cached_ctx.TEX0.PSM & 0x6) || m_cached_ctx.FRAME.PSM != m_cached_ctx.TEX0.PSM))*/) || IsPossibleChannelShuffle());
Expand Down Expand Up @@ -2830,6 +2846,7 @@ void GSRendererHW::Draw()
if (!possible_shuffle && m_split_texture_shuffle_pages == 0)
m_r = m_r.rintersect(t_size_rect);

GSVector4i lookup_rect = unclamped_draw_rect;
// Do the lookup with the real format on a shuffle, if possible.
if (possible_shuffle && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16 && GSLocalMemory ::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16)
{
Expand All @@ -2843,6 +2860,22 @@ void GSRendererHW::Draw()
FRAME_TEX0.PSM = next_ctx.TEX0.PSM;
else
FRAME_TEX0.PSM = PSMCT32; // Guess full color if no upcoming hint, it'll fix itself later.

// This is just for overlap detection, it doesn't matter which direction we do this in
if (GSLocalMemory::m_psm[FRAME_TEX0.PSM].bpp == 32)
{
// Shuffling with a double width (Sonic Unleashed for example which does a wierd shuffle/not shuffle green backup/restore).
if (src && std::abs((lookup_rect.width() / 2) - src->m_from_target->m_unscaled_size.x) <= 8)
{
lookup_rect.x /= 2;
lookup_rect.z /= 2;
}
else
{
lookup_rect.y /= 2;
lookup_rect.w /= 2;
}
}
}

// Normally we would use 1024 here to match the clear above, but The Godfather does a 1023x1023 draw instead
Expand All @@ -2856,7 +2889,7 @@ void GSRendererHW::Draw()
const bool preserve_downscale_draw = scale_draw < 0 || (scale_draw == 0 && ((src && src->m_from_target && src->m_from_target->m_downscaled) || is_possible_mem_clear == ClearType::ClearWithDraw));

rt = g_texture_cache->LookupTarget(FRAME_TEX0, t_size, ((src && src->m_scale != 1) && GSConfig.UserHacks_NativeScaling == GSNativeScaling::Normal && !possible_shuffle) ? GetTextureScaleFactor() : 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, lookup_rect, possible_shuffle, is_possible_mem_clear && FRAME_TEX0.TBP0 != m_cached_ctx.ZBUF.Block(),
GSConfig.UserHacks_NativeScaling != GSNativeScaling::Off && preserve_downscale_draw && is_possible_mem_clear != ClearType::NormalClear, src, (no_ds || !ds) ? -1 : (m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0));

// Draw skipped because it was a clear and there was no target.
Expand Down Expand Up @@ -2895,7 +2928,7 @@ void GSRendererHW::Draw()
else if (rt->m_TEX0.TBP0 != m_cached_ctx.FRAME.Block())
{
int vertical_offset = ((static_cast<int>(m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) / 32) / std::max(static_cast<int>(rt->m_TEX0.TBW), 1)) * frame_psm.pgs.y; // I know I could just not shift it..

int texture_offset = 0;
const int horizontal_offset = ((static_cast<int>((m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0)) / 32) % static_cast<int>(std::max(rt->m_TEX0.TBW, 1U))) * frame_psm.pgs.x;
// Used to reduce the offset made later in channel shuffles
m_target_offset = std::abs(static_cast<int>((m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0)) >> 5);
Expand All @@ -2906,6 +2939,7 @@ void GSRendererHW::Draw()
GSVector2i new_scaled_size = rt->m_unscaled_size * rt->m_scale;
// Make sure to use the original format for the offset.
int new_offset = std::abs((vertical_offset / frame_psm.pgs.y) * GSLocalMemory::m_psm[rt->m_TEX0.PSM].pgs.y);
texture_offset = new_offset;

new_scaled_size.y += new_offset * rt->m_scale;
GSTexture* tex = g_gs_device->CreateRenderTarget(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::Color, true);
Expand All @@ -2916,18 +2950,13 @@ void GSRendererHW::Draw()
g_gs_device->StretchRect(rt->m_texture, GSVector4(0,0,1,1), tex, GSVector4(dRect), ShaderConvert::COPY, false);


if (src && src->m_from_target && src->m_from_target == rt)
{
src->m_texture = rt->m_texture;
src->m_target_direct = false;
src->m_shared_texture = false;
}
else
if (src && src->m_from_target && src->m_from_target == rt && src->m_target_direct)
{
//m_target_memory_usage -= dst->m_texture->GetMemUsage();
g_gs_device->Recycle(rt->m_texture);
src->m_texture = tex;
}

g_gs_device->Recycle(rt->m_texture);

rt->m_valid.y += new_offset;
rt->m_valid.w += new_offset;
rt->m_drawn_since_read.y += new_offset;
Expand Down Expand Up @@ -2958,8 +2987,26 @@ void GSRendererHW::Draw()

for (u32 i = 0; i < m_vertex.tail; i++)
{
v[i].XYZ.Y += vertical_offset << 4;
v[i].XYZ.X += horizontal_offset << 4;
v[i].XYZ.Y += vertical_offset << 4;
}

if (texture_offset && src && src->m_from_target && src->m_target_direct && src->m_from_target == rt)
{
GSVector4i src_region = src->GetRegionRect();

if (src_region.rempty())
{
src_region = GSVector4i::loadh(rt->m_unscaled_size);
src_region.y += texture_offset;
}
else
{
src_region.y += texture_offset;
src_region.w += texture_offset;
}
src->m_region.SetX(src_region.x, src_region.z);
src->m_region.SetY(src_region.y, src_region.w);
}

m_context->scissor.in.x += horizontal_offset;
Expand Down Expand Up @@ -3004,6 +3051,7 @@ void GSRendererHW::Draw()
src->m_texture = rt->m_texture;
src->m_scale = rt->GetScale();
src->m_unscaled_size = rt->m_unscaled_size;

}

target_scale = rt->GetScale();
Expand Down Expand Up @@ -3414,7 +3462,7 @@ void GSRendererHW::Draw()
GL_INS("Resize RT from %dx%d to %dx%d", rt->GetUnscaledWidth(), rt->GetUnscaledHeight(), new_w, new_h);

// May not be needed/could cause problems with garbage loaded from GS memory
if (preserve_rt_color)
/*if (preserve_rt_color)
{
RGBAMask mask;
mask._u32 = 0xF;
Expand All @@ -3430,7 +3478,7 @@ void GSRendererHW::Draw()
GSVector4i height_dirty_rect = GSVector4i(0, rt->m_unscaled_size.y, new_w, new_h);
g_texture_cache->AddDirtyRectTarget(rt, height_dirty_rect, rt->m_TEX0.PSM, rt->m_TEX0.TBW, mask);
}
}
}*/

rt->ResizeTexture(new_w, new_h);

Expand Down Expand Up @@ -3489,6 +3537,7 @@ void GSRendererHW::Draw()
pxAssert(ds->GetScale() == target_scale);
if (ds->GetUnscaledWidth() != new_w || ds->GetUnscaledHeight() != new_h)
GL_INS("Resize DS from %dx%d to %dx%d", ds->GetUnscaledWidth(), ds->GetUnscaledHeight(), new_w, new_h);

ds->ResizeTexture(new_w, new_h);

if (!m_texture_shuffle && !m_channel_shuffle)
Expand Down
Loading

0 comments on commit 030f752

Please sign in to comment.