Compare commits

...

16 Commits

Author SHA1 Message Date
refractionpcsx2 42aba2e0db
Merge afc0c2581d into de9d08075e 2025-01-17 11:09:04 +00:00
refractionpcsx2 afc0c2581d GS/HW: Further fixes to HW renderer behaviour 2025-01-17 11:08:48 +00:00
refractionpcsx2 f015b14e50 GS/HW: Don't interfere with Tales/Urban Chaos HLE shuffles 2025-01-17 10:02:33 +00:00
refractionpcsx2 fd53ce2ec6 GS/HW: Allow 1:1 quads to be optimized for textures. Fixes for shuffles 2025-01-17 10:02:33 +00:00
refractionpcsx2 1ac2d9fba3 GS/HW: Centralize new target resizing calls to fix statistics/tidy up
Also add an override for GSVector4i loadl to take a GSVector2i
2025-01-17 10:02:33 +00:00
refractionpcsx2 80e50b87f7 GS/HW: Fixes for Tex in RT and shuffle detection 2025-01-17 10:02:33 +00:00
refractionpcsx2 4d37a9721f GS/HW: Sync depth texture information when updating dst_match 2025-01-17 10:02:33 +00:00
refractionpcsx2 8de5f53252 GS/HW: Fix some back to back shuffles and inside source invalidation 2025-01-17 10:02:32 +00:00
refractionpcsx2 e9341bde7c GS/HW: Fix offset Z channel shuffle hazard. Adjust Tekken 5 CRC 2025-01-17 10:02:32 +00:00
refractionpcsx2 da3e5c0aad GS/HW: More changes some regressions 2025-01-17 10:02:32 +00:00
refractionpcsx2 7b9c5b7543 GS/HW: More alterations for new RT in RT system 2025-01-17 10:02:32 +00:00
refractionpcsx2 9ddb4980eb GS/HW: Fixes to texture is target offsets 2025-01-17 10:02:31 +00:00
refractionpcsx2 99f7db509e GS/HW: Further fixes for RT in RT changes in behaviour 2025-01-17 10:02:31 +00:00
refractionpcsx2 3b17ccac36 GS/HW: Further RT in RT changes to improve compatibility 2025-01-17 10:02:31 +00:00
refractionpcsx2 8865ad90ff GS/HW: Further fixes to RT in RT - Still a ways to go... 2025-01-17 10:02:31 +00:00
refractionpcsx2 9d6e500035 GS/HW: Initial work implementing RT in RT support 2025-01-17 10:02:30 +00:00
13 changed files with 1180 additions and 334 deletions

View File

@ -1967,6 +1967,7 @@ SCAJ-20125:
clampModes: clampModes:
eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove. eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove.
gsHWFixes: gsHWFixes:
textureInsideRT: 1 # Fixes heat haze half screen problem.
alignSprite: 1 alignSprite: 1
halfPixelOffset: 4 # Align post. halfPixelOffset: 4 # Align post.
nativeScaling: 1 # Fixes depth of field effect. nativeScaling: 1 # Fixes depth of field effect.
@ -1977,6 +1978,7 @@ SCAJ-20126:
clampModes: clampModes:
eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove. eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove.
gsHWFixes: gsHWFixes:
textureInsideRT: 1 # Fixes heat haze half screen problem.
alignSprite: 1 alignSprite: 1
halfPixelOffset: 4 # Align post. halfPixelOffset: 4 # Align post.
nativeScaling: 1 # Fixes depth of field effect. nativeScaling: 1 # Fixes depth of field effect.
@ -2454,6 +2456,7 @@ SCAJ-20199:
clampModes: clampModes:
eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove. eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove.
gsHWFixes: gsHWFixes:
textureInsideRT: 1 # Fixes heat haze half screen problem.
alignSprite: 1 alignSprite: 1
halfPixelOffset: 4 # Align post. halfPixelOffset: 4 # Align post.
nativeScaling: 1 # Fixes depth of field effect. nativeScaling: 1 # Fixes depth of field effect.
@ -4149,6 +4152,7 @@ SCED-53538:
clampModes: clampModes:
eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove. eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove.
gsHWFixes: gsHWFixes:
textureInsideRT: 1 # Fixes heat haze half screen problem.
alignSprite: 1 alignSprite: 1
halfPixelOffset: 4 # Align post. halfPixelOffset: 4 # Align post.
nativeScaling: 1 # Fixes depth of field effect. nativeScaling: 1 # Fixes depth of field effect.
@ -5769,6 +5773,7 @@ SCES-53202:
clampModes: clampModes:
eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove. eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove.
gsHWFixes: gsHWFixes:
textureInsideRT: 1 # Fixes heat haze half screen problem.
alignSprite: 1 alignSprite: 1
halfPixelOffset: 4 # Align post. halfPixelOffset: 4 # Align post.
nativeScaling: 1 # Fixes depth of field effect. nativeScaling: 1 # Fixes depth of field effect.
@ -7212,6 +7217,7 @@ SCKA-20049:
clampModes: clampModes:
eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove. eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove.
gsHWFixes: gsHWFixes:
textureInsideRT: 1 # Fixes heat haze half screen problem.
alignSprite: 1 alignSprite: 1
halfPixelOffset: 4 # Align post. halfPixelOffset: 4 # Align post.
nativeScaling: 1 # Fixes depth of field effect. nativeScaling: 1 # Fixes depth of field effect.
@ -7435,6 +7441,7 @@ SCKA-20081:
clampModes: clampModes:
eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove. eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove.
gsHWFixes: gsHWFixes:
textureInsideRT: 1 # Fixes heat haze half screen problem.
alignSprite: 1 alignSprite: 1
halfPixelOffset: 4 # Align post. halfPixelOffset: 4 # Align post.
nativeScaling: 1 # Fixes depth of field effect. nativeScaling: 1 # Fixes depth of field effect.
@ -57353,6 +57360,7 @@ SLPS-25510:
clampModes: clampModes:
eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove. eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove.
gsHWFixes: gsHWFixes:
textureInsideRT: 1 # Fixes heat haze half screen problem.
alignSprite: 1 # Fixes vertical lines. alignSprite: 1 # Fixes vertical lines.
halfPixelOffset: 4 # Align post. halfPixelOffset: 4 # Align post.
nativeScaling: 1 # Fixes depth of field effect. nativeScaling: 1 # Fixes depth of field effect.
@ -60518,6 +60526,7 @@ SLPS-73223:
clampModes: clampModes:
eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove. eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove.
gsHWFixes: gsHWFixes:
textureInsideRT: 1 # Fixes heat haze half screen problem.
alignSprite: 1 # Fixes vertical lines. alignSprite: 1 # Fixes vertical lines.
halfPixelOffset: 4 # Align post. halfPixelOffset: 4 # Align post.
nativeScaling: 1 # Fixes depth of field effect. nativeScaling: 1 # Fixes depth of field effect.
@ -66516,6 +66525,7 @@ SLUS-21059:
clampModes: clampModes:
eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove. eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove.
gsHWFixes: gsHWFixes:
textureInsideRT: 1 # Fixes heat haze half screen problem.
alignSprite: 1 # Fixes vertical lines. alignSprite: 1 # Fixes vertical lines.
halfPixelOffset: 4 # Align post. halfPixelOffset: 4 # Align post.
nativeScaling: 1 # Fixes depth of field effect. nativeScaling: 1 # Fixes depth of field effect.
@ -67060,6 +67070,7 @@ SLUS-21160:
clampModes: clampModes:
eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove. eeClampMode: 2 # Fixes camera and stops constant coin noises on Pirates Cove.
gsHWFixes: gsHWFixes:
textureInsideRT: 1 # Fixes heat haze half screen problem.
alignSprite: 1 # Fixes vertical lines. alignSprite: 1 # Fixes vertical lines.
halfPixelOffset: 4 # Align post. halfPixelOffset: 4 # Align post.
nativeScaling: 1 # Fixes depth of field effect. nativeScaling: 1 # Fixes depth of field effect.

View File

@ -1123,11 +1123,8 @@ PS_OUTPUT ps_main(PS_INPUT input)
{ {
if (PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE) if (PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
{ {
C.rb = C.br; C.br = C.rb;
float g_temp = C.g; C.ag = C.ga;
C.g = C.a;
C.a = g_temp;
} }
else if(PS_PROCESS_BA & SHUFFLE_READ) else if(PS_PROCESS_BA & SHUFFLE_READ)
{ {

View File

@ -1086,11 +1086,8 @@ void ps_main()
C.ga = vec2(float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80u))); C.ga = vec2(float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80u)));
#elif PS_SHUFFLE_ACROSS #elif PS_SHUFFLE_ACROSS
#if(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE) #if(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
C.rb = C.br; C.br = C.rb;
float g_temp = C.g; C.ag = C.ga;
C.g = C.a;
C.a = g_temp;
#elif(PS_PROCESS_BA & SHUFFLE_READ) #elif(PS_PROCESS_BA & SHUFFLE_READ)
C.rb = C.bb; C.rb = C.bb;
C.ga = C.aa; C.ga = C.aa;

View File

@ -945,7 +945,7 @@ vec4 ps_color()
vec4 T = sample_color(st); vec4 T = sample_color(st);
#endif #endif
#if PS_SHUFFLE && !PS_READ16_SRC && !PS_SHUFFLE_SAME #if PS_SHUFFLE && !PS_READ16_SRC && !PS_SHUFFLE_SAME && !(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
uvec4 denorm_c_before = uvec4(T); uvec4 denorm_c_before = uvec4(T);
#if (PS_PROCESS_BA & SHUFFLE_READ) #if (PS_PROCESS_BA & SHUFFLE_READ)
T.r = float((denorm_c_before.b << 3) & 0xF8u); T.r = float((denorm_c_before.b << 3) & 0xF8u);
@ -1320,7 +1320,7 @@ void main()
ps_blend(C, alpha_blend); ps_blend(C, alpha_blend);
#if PS_SHUFFLE #if PS_SHUFFLE
#if !PS_READ16_SRC && !PS_SHUFFLE_SAME #if !PS_READ16_SRC && !PS_SHUFFLE_SAME && !(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
uvec4 denorm_c_after = uvec4(C); uvec4 denorm_c_after = uvec4(C);
#if (PS_PROCESS_BA & SHUFFLE_READ) #if (PS_PROCESS_BA & SHUFFLE_READ)
C.b = float(((denorm_c_after.r >> 3) & 0x1Fu) | ((denorm_c_after.g << 2) & 0xE0u)); C.b = float(((denorm_c_after.r >> 3) & 0x1Fu) | ((denorm_c_after.g << 2) & 0xE0u));
@ -1350,11 +1350,8 @@ void main()
// Write RB part. Mask will take care of the correct destination // Write RB part. Mask will take care of the correct destination
#elif PS_SHUFFLE_ACROSS #elif PS_SHUFFLE_ACROSS
#if(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE) #if(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
C.rb = C.br; C.br = C.rb;
float g_temp = C.g; C.ag = C.ga;
C.g = C.a;
C.a = g_temp;
#elif(PS_PROCESS_BA & SHUFFLE_READ) #elif(PS_PROCESS_BA & SHUFFLE_READ)
C.rb = C.bb; C.rb = C.bb;
C.ga = C.aa; C.ga = C.aa;

View File

@ -467,7 +467,8 @@ void GSState::DumpVertices(const std::string& filename)
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.R) << DEL; file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.R) << DEL;
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.G) << DEL; file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.G) << DEL;
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.B) << DEL; file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.B) << DEL;
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.A); file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.A) << DEL;
file << "FOG: " << std::setfill('0') << std::setw(3) << unsigned(v.FOG);
file << std::endl; file << std::endl;
} }
@ -1674,7 +1675,8 @@ void GSState::FlushPrim()
Console.Warning("GS: Possible invalid draw, Frame PSM %x ZPSM %x", m_context->FRAME.PSM, m_context->ZBUF.PSM); Console.Warning("GS: Possible invalid draw, Frame PSM %x ZPSM %x", m_context->FRAME.PSM, m_context->ZBUF.PSM);
} }
#endif #endif
// Update scissor, it may have been modified by a previous draw
m_env.CTXT[PRIM->CTXT].UpdateScissor();
m_vt.Update(m_vertex.buff, m_index.buff, m_vertex.tail, m_index.tail, GSUtil::GetPrimClass(PRIM->PRIM)); m_vt.Update(m_vertex.buff, m_index.buff, m_vertex.tail, m_index.tail, GSUtil::GetPrimClass(PRIM->PRIM));
// Texel coordinate rounding // Texel coordinate rounding
@ -3094,6 +3096,16 @@ __forceinline bool GSState::IsAutoFlushDraw(u32 prim)
if (!(GSUtil::GetChannelMask(m_context->TEX0.PSM) & GSUtil::GetChannelMask(m_context->FRAME.PSM, m_context->FRAME.FBMSK | ~(GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk)))) if (!(GSUtil::GetChannelMask(m_context->TEX0.PSM) & GSUtil::GetChannelMask(m_context->FRAME.PSM, m_context->FRAME.FBMSK | ~(GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk))))
return false; return false;
// Try to detect shuffles, because these will not autoflush, they by design clash.
if (GSLocalMemory::m_psm[m_context->FRAME.PSM].bpp == 16 && GSLocalMemory::m_psm[m_context->TEX0.PSM].bpp == 16)
{
// Pretty confident here...
GSVertex* buffer = &m_vertex.buff[0];
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;
}
const u32 frame_mask = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk; const u32 frame_mask = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk;
const bool frame_hit = m_context->FRAME.Block() == m_context->TEX0.TBP0 && !(m_context->TEST.ATE && m_context->TEST.ATST == 0 && m_context->TEST.AFAIL == 2) && ((m_context->FRAME.FBMSK & frame_mask) != frame_mask); const bool frame_hit = m_context->FRAME.Block() == m_context->TEX0.TBP0 && !(m_context->TEST.ATE && m_context->TEST.ATST == 0 && m_context->TEST.AFAIL == 2) && ((m_context->FRAME.FBMSK & frame_mask) != frame_mask);
// There's a strange behaviour we need to test on a PS2 here, if the FRAME is a Z format, like Powerdrome something swaps over, and it seems Alpha Fail of "FB Only" writes to the Z.. it's odd. // There's a strange behaviour we need to test on a PS2 here, if the FRAME is a Z format, like Powerdrome something swaps over, and it seems Alpha Fail of "FB Only" writes to the Z.. it's odd.
@ -3859,7 +3871,8 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
const GSVector2 grad(uv_range / pos_range); const GSVector2 grad(uv_range / pos_range);
// Adjust texture range when sprites get scissor clipped. Since we linearly interpolate, this // Adjust texture range when sprites get scissor clipped. Since we linearly interpolate, this
// optimization doesn't work when perspective correction is enabled. // optimization doesn't work when perspective correction is enabled.
if (m_vt.m_primclass == GS_SPRITE_CLASS && PRIM->FST == 1 && m_primitive_covers_without_gaps != NoGapsType::GapsFound) // Allowing for quads when the gradiant is 1. It's not guaranteed (would need to check the grandient on each vector), but should be close enough.
if ((m_vt.m_primclass == GS_SPRITE_CLASS || (m_vt.m_primclass == GS_TRIANGLE_CLASS && TrianglesAreQuads(false) && grad.x == 1.0f && grad.y == 1.0f)) && m_primitive_covers_without_gaps != NoGapsType::GapsFound)
{ {
// When coordinates are fractional, GS appears to draw to the right/bottom (effectively // When coordinates are fractional, GS appears to draw to the right/bottom (effectively
// taking the ceiling), not to the top/left (taking the floor). // taking the ceiling), not to the top/left (taking the floor).
@ -3870,11 +3883,24 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
const GSVertex* vert_first = &m_vertex.buff[m_index.buff[0]]; const GSVertex* vert_first = &m_vertex.buff[m_index.buff[0]];
const GSVertex* vert_second = &m_vertex.buff[m_index.buff[1]]; const GSVertex* vert_second = &m_vertex.buff[m_index.buff[1]];
const GSVertex* vert_third = &m_vertex.buff[m_index.buff[2]];
GSVector4 new_st = st; GSVector4 new_st = st;
bool u_forward_check = false;
bool x_forward_check = false;
if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
{
u_forward_check = PRIM->FST ? ((vert_first->U < vert_second->U) || (vert_first->U < vert_third->U)) : (((vert_first->ST.S / vert_first->RGBAQ.Q) < (vert_second->ST.S / vert_second->RGBAQ.Q)) || ((vert_first->ST.S / vert_first->RGBAQ.Q) < (vert_third->ST.S / vert_third->RGBAQ.Q)));
x_forward_check = (vert_first->XYZ.X < vert_second->XYZ.X) || (vert_first->XYZ.X < vert_third->XYZ.X);
}
else
{
u_forward_check = PRIM->FST ? (vert_first->U < vert_second->U) : ((vert_first->ST.T / vert_first->RGBAQ.Q) < (vert_second->ST.T / vert_first->RGBAQ.Q));
x_forward_check = vert_first->XYZ.Y < vert_second->XYZ.Y;
}
// Check if the UV coords are going in a different direction to the verts, if they match direction, no need to swap // Check if the UV coords are going in a different direction to the verts, if they match direction, no need to swap
const bool u_forward = vert_first->U < vert_second->U; const bool u_forward = u_forward_check;
const bool x_forward = vert_first->XYZ.X < vert_second->XYZ.X; const bool x_forward = x_forward_check;
const bool swap_x = u_forward != x_forward; const bool swap_x = u_forward != x_forward;
if (int_rc.left < scissored_rc.left) if (int_rc.left < scissored_rc.left)
@ -3897,9 +3923,20 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
st.x = new_st.x; st.x = new_st.x;
st.z = new_st.z; st.z = new_st.z;
} }
bool v_forward_check = false;
const bool v_forward = vert_first->V < vert_second->V; bool y_forward_check = false;
const bool y_forward = vert_first->XYZ.Y < vert_second->XYZ.Y; if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
{
v_forward_check = PRIM->FST ? ((vert_first->V < vert_second->V) || (vert_first->V < vert_third->V)) : (((vert_first->ST.T / vert_first->RGBAQ.Q) < (vert_second->ST.T / vert_second->RGBAQ.Q)) || ((vert_first->ST.T / vert_first->RGBAQ.Q) < (vert_third->ST.T / vert_third->RGBAQ.Q)));
y_forward_check = (vert_first->XYZ.Y < vert_second->XYZ.Y) || (vert_first->XYZ.Y < vert_third->XYZ.Y);
}
else
{
v_forward_check = PRIM->FST ? (vert_first->V < vert_second->V) : ((vert_first->ST.T / vert_first->RGBAQ.Q) < (vert_second->ST.T / vert_first->RGBAQ.Q));
y_forward_check = vert_first->XYZ.Y < vert_second->XYZ.Y;
}
const bool v_forward = v_forward_check;
const bool y_forward = y_forward_check;
const bool swap_y = v_forward != y_forward; const bool swap_y = v_forward != y_forward;
if (int_rc.top < scissored_rc.top) if (int_rc.top < scissored_rc.top)

View File

@ -224,6 +224,8 @@ public:
bool m_texflush_flag = false; bool m_texflush_flag = false;
bool m_isPackedUV_HackFlag = false; bool m_isPackedUV_HackFlag = false;
bool m_channel_shuffle = false; bool m_channel_shuffle = false;
bool m_in_target_draw = false;
u32 m_target_offset = 0;
u8 m_scanmask_used = 0; u8 m_scanmask_used = 0;
u32 m_dirty_gs_regs = 0; u32 m_dirty_gs_regs = 0;
int m_backed_up_ctx = 0; int m_backed_up_ctx = 0;

View File

@ -1599,6 +1599,11 @@ public:
return loadh(&v); return loadh(&v);
} }
__forceinline static GSVector4i loadl(const GSVector2i& v)
{
return loadl(&v);
}
__forceinline static GSVector4i load(const void* pl, const void* ph) __forceinline static GSVector4i load(const void* pl, const void* ph)
{ {
return loadh(ph, loadl(pl)); return loadh(ph, loadl(pl));

View File

@ -194,7 +194,7 @@ bool GSHwHack::GSC_Tekken5(GSRendererHW& r, int& skip)
return true; return true;
} }
if (!s_nativeres && r.PRIM->PRIM == GS_SPRITE && RTME && RTEX0.TFX == 1 && RFPSM == RTPSM && RTPSM == PSMCT32 && RFBMSK == 0xFF000000 && r.m_index.tail > 2) if (!s_nativeres && r.PRIM->PRIM == GS_SPRITE && RTME && RTEX0.TFX == 1 && !r.PRIM->ABE && RFPSM == RTPSM && RTPSM == PSMCT32 && RFBMSK == 0xFF000000 && r.m_index.tail > 2)
{ {
// Don't enable hack on native res. // Don't enable hack on native res.
// Fixes ghosting/blur effect and white lines appearing in stages: Moonfit Wilderness, Acid Rain - caused by upscaling. // Fixes ghosting/blur effect and white lines appearing in stages: Moonfit Wilderness, Acid Rain - caused by upscaling.
@ -204,12 +204,6 @@ bool GSHwHack::GSC_Tekken5(GSRendererHW& r, int& skip)
const GSVector4i read_size(r.m_vt.m_min.t.x, r.m_vt.m_min.t.y, r.m_vt.m_max.t.x + 0.5f, r.m_vt.m_max.t.y + 0.5f); const GSVector4i read_size(r.m_vt.m_min.t.x, r.m_vt.m_min.t.y, r.m_vt.m_max.t.x + 0.5f, r.m_vt.m_max.t.y + 0.5f);
r.ReplaceVerticesWithSprite(draw_size, read_size, GSVector2i(read_size.width(), read_size.height()), draw_size); r.ReplaceVerticesWithSprite(draw_size, read_size, GSVector2i(read_size.width(), read_size.height()), draw_size);
} }
else if (RZTST == 1 && RTME && (RFBP == 0x02bc0 || RFBP == 0x02be0 || RFBP == 0x02d00 || RFBP == 0x03480 || RFBP == 0x034a0) && RFPSM == RTPSM && RTBP0 == 0x00000 && RTPSM == PSMCT32)
{
// The moving display effect(flames) is not emulated properly in the entire screen so let's remove the effect in the stage: Burning Temple. Related to half screen bottom issue.
// Fixes black lines in the stage: Burning Temple - caused by upscaling. Note the black lines can also be fixed with Merge Sprite hack.
skip = 2;
}
} }
return true; return true;
@ -1047,7 +1041,7 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
// compute shadow in RG, // compute shadow in RG,
// save result in alpha with a TS, // save result in alpha with a TS,
// Restore RG channel that we previously copied to render shadows. // 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; const GIFRegTEX0& Texture = RTEX0;
GIFRegTEX0 Frame = {}; GIFRegTEX0 Frame = {};
@ -1058,9 +1052,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)) 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; 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) if (!src)
return true; return true;
@ -1086,6 +1080,7 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
const GSVector2i copy_size(std::min(rt_size.x, src_size.x), std::min(rt_size.y, src_size.y)); const GSVector2i copy_size(std::min(rt_size.x, src_size.x), std::min(rt_size.y, src_size.y));
const GSVector4 sRect(0.0f, 0.0f, static_cast<float>(copy_size.x) / static_cast<float>(src_size.x), static_cast<float>(copy_size.y) / static_cast<float>(src_size.y)); const GSVector4 sRect(0.0f, 0.0f, static_cast<float>(copy_size.x) / static_cast<float>(src_size.x), static_cast<float>(copy_size.y) / static_cast<float>(src_size.y));
// This is kind of a bodge because the game confuses everything since the source is really 16bit and it assumes it's really drawing 16bit on the copy back, resizing the target.
const GSVector4 dRect(0, 0, copy_size.x, copy_size.y); const GSVector4 dRect(0, 0, copy_size.x, copy_size.y);
g_gs_device->StretchRect(src->m_texture, sRect, rt, dRect, true, true, true, false); g_gs_device->StretchRect(src->m_texture, sRect, rt, dRect, true, true, true, false);

File diff suppressed because it is too large Load Diff

View File

@ -113,12 +113,14 @@ private:
void SetTCOffset(); void SetTCOffset();
bool IsPossibleChannelShuffle() const; bool IsPossibleChannelShuffle() const;
bool IsPageCopy() const;
bool NextDrawMatchesShuffle() const; bool NextDrawMatchesShuffle() const;
bool IsSplitTextureShuffle(GSTextureCache::Target* rt); bool IsSplitTextureShuffle(GSTextureCache::Target* rt);
GSVector4i GetSplitTextureShuffleDrawRect() const; GSVector4i GetSplitTextureShuffleDrawRect() const;
u32 GetEffectiveTextureShuffleFbmsk() const; u32 GetEffectiveTextureShuffleFbmsk() const;
static GSVector4i GetDrawRectForPages(u32 bw, u32 psm, u32 num_pages); static GSVector4i GetDrawRectForPages(u32 bw, u32 psm, u32 num_pages);
bool IsSinglePageDraw() const;
bool TryToResolveSinglePageFramebuffer(GIFRegFRAME& FRAME, bool only_next_draw); bool TryToResolveSinglePageFramebuffer(GIFRegFRAME& FRAME, bool only_next_draw);
bool IsSplitClearActive() const; bool IsSplitClearActive() const;
@ -172,6 +174,7 @@ private:
u32 m_last_channel_shuffle_fbmsk = 0; u32 m_last_channel_shuffle_fbmsk = 0;
u32 m_last_channel_shuffle_fbp = 0; u32 m_last_channel_shuffle_fbp = 0;
u32 m_last_channel_shuffle_tbp = 0;
u32 m_last_channel_shuffle_end_block = 0; u32 m_last_channel_shuffle_end_block = 0;
GIFRegFRAME m_split_clear_start = {}; GIFRegFRAME m_split_clear_start = {};

File diff suppressed because it is too large Load Diff

View File

@ -257,7 +257,7 @@ public:
void UpdateValidChannels(u32 psm, u32 fbmsk); void UpdateValidChannels(u32 psm, u32 fbmsk);
/// Resizes target texture, DOES NOT RESCALE. /// Resizes target texture, DOES NOT RESCALE.
bool ResizeTexture(int new_unscaled_width, int new_unscaled_height, bool recycle_old = true); bool ResizeTexture(int new_unscaled_width, int new_unscaled_height, bool recycle_old = true, bool require_offset = false, GSVector4i offset = GSVector4i::zero(), bool keep_old = false);
private: private:
void UpdateTextureDebugName(); void UpdateTextureDebugName();
@ -427,6 +427,7 @@ protected:
std::unordered_map<SurfaceOffsetKey, SurfaceOffset, SurfaceOffsetKeyHash, SurfaceOffsetKeyEqual> m_surface_offset_cache; std::unordered_map<SurfaceOffsetKey, SurfaceOffset, SurfaceOffsetKeyHash, SurfaceOffsetKeyEqual> m_surface_offset_cache;
Source* m_temporary_source = nullptr; // invalidated after the draw Source* m_temporary_source = nullptr; // invalidated after the draw
GSTexture* m_temporary_z = nullptr; // invalidated after the draw
std::unique_ptr<GSDownloadTexture> m_color_download_texture; std::unique_ptr<GSDownloadTexture> m_color_download_texture;
std::unique_ptr<GSDownloadTexture> m_uint16_download_texture; std::unique_ptr<GSDownloadTexture> m_uint16_download_texture;
@ -491,7 +492,7 @@ 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, bool preserve_scale = false); const GSVector4i draw_rc = GSVector4i::zero(), bool is_shuffle = false, bool possible_clear = false, bool preserve_scale = false, GSTextureCache::Source* src = nullptr, int offset = -1);
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);
@ -508,7 +509,7 @@ public:
bool HasTargetInHeightCache(u32 bp, u32 fbw, u32 psm, u32 max_age = std::numeric_limits<u32>::max(), bool move_front = true); bool HasTargetInHeightCache(u32 bp, u32 fbw, u32 psm, u32 max_age = std::numeric_limits<u32>::max(), bool move_front = true);
bool Has32BitTarget(u32 bp); bool Has32BitTarget(u32 bp);
void InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 write_psm = PSMCT32); void InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 write_psm = PSMCT32, u32 write_bw = 1);
void InvalidateVideoMemType(int type, u32 bp, u32 write_psm = PSMCT32, u32 write_fbmsk = 0, bool dirty_only = false); void InvalidateVideoMemType(int type, u32 bp, u32 write_psm = PSMCT32, u32 write_fbmsk = 0, bool dirty_only = false);
void InvalidateVideoMemSubTarget(GSTextureCache::Target* rt); void InvalidateVideoMemSubTarget(GSTextureCache::Target* rt);
void InvalidateVideoMem(const GSOffset& off, const GSVector4i& r, bool target = true); void InvalidateVideoMem(const GSOffset& off, const GSVector4i& r, bool target = true);
@ -517,7 +518,7 @@ public:
/// Removes any sources which point to the specified target. /// Removes any sources which point to the specified target.
void InvalidateSourcesFromTarget(const Target* t); void InvalidateSourcesFromTarget(const Target* t);
/// Replaces a source's texture externally. Required for some CRC hacks. /// Removes any sources which point to the same address as a new target.
void ReplaceSourceTexture(Source* s, GSTexture* new_texture, float new_scale, const GSVector2i& new_unscaled_size, void ReplaceSourceTexture(Source* s, GSTexture* new_texture, float new_scale, const GSVector2i& new_unscaled_size,
HashCacheEntry* hc_entry, bool new_texture_is_shared); HashCacheEntry* hc_entry, bool new_texture_is_shared);
@ -551,6 +552,11 @@ public:
/// Invalidates a temporary source, a partial copy only created from the current RT/DS for the current draw. /// Invalidates a temporary source, a partial copy only created from the current RT/DS for the current draw.
void InvalidateTemporarySource(); void InvalidateTemporarySource();
void SetTemporaryZ(GSTexture* temp_z);
GSTexture* GetTemporaryZ();
/// Invalidates a temporary Z, a partial copy only created from the current DS for the current draw when Z is not offset but RT is
void InvalidateTemporaryZ();
/// Injects a texture into the hash cache, by using GSTexture::Swap(), transitively applying to all sources. Ownership of tex is transferred. /// Injects a texture into the hash cache, by using GSTexture::Swap(), transitively applying to all sources. Ownership of tex is transferred.
void InjectHashCacheTexture(const HashCacheKey& key, GSTexture* tex, const std::pair<u8, u8>& alpha_minmax); void InjectHashCacheTexture(const HashCacheKey& key, GSTexture* tex, const std::pair<u8, u8>& alpha_minmax);

View File

@ -1168,11 +1168,8 @@ struct PSMain
{ {
if (PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE) if (PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
{ {
C.rb = C.br; C.br = C.rb;
float g_temp = C.g; C.ag = C.ga;
C.g = C.a;
C.a = g_temp;
} }
else if(PS_PROCESS_BA & SHUFFLE_READ) else if(PS_PROCESS_BA & SHUFFLE_READ)
{ {