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

GS/HW: Implement RT in RT support #11461

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6e3c33a
GS/HW: Initial work implementing RT in RT support
refractionpcsx2 Mar 30, 2024
6254c97
GS/HW: Further fixes to RT in RT - Still a ways to go...
refractionpcsx2 Jun 26, 2024
c2256e7
GS/HW: Further RT in RT changes to improve compatibility
refractionpcsx2 Jul 2, 2024
f1f11f8
GS/HW: Further fixes for RT in RT changes in behaviour
refractionpcsx2 Jan 1, 2025
8857736
GS/HW: Fixes to texture is target offsets
refractionpcsx2 Jan 6, 2025
12cdc86
GS/HW: More alterations for new RT in RT system
refractionpcsx2 Jan 11, 2025
2d62f2f
GS/HW: More changes some regressions
refractionpcsx2 Jan 12, 2025
547c4ab
GS/HW: Fix offset Z channel shuffle hazard. Adjust Tekken 5 CRC
refractionpcsx2 Jan 14, 2025
b8d5b36
GS/HW: Fix some back to back shuffles and inside source invalidation
refractionpcsx2 Jan 14, 2025
da261c1
GS/HW: Sync depth texture information when updating dst_match
refractionpcsx2 Jan 15, 2025
6c9a115
GS/HW: Fixes for Tex in RT and shuffle detection
refractionpcsx2 Jan 16, 2025
4f11ea0
GS/HW: Centralize new target resizing calls to fix statistics/tidy up
refractionpcsx2 Jan 16, 2025
29976f5
GS/HW: Allow 1:1 quads to be optimized for textures. Fixes for shuffles
refractionpcsx2 Jan 16, 2025
a127516
GS/HW: Don't interfere with Tales/Urban Chaos HLE shuffles
refractionpcsx2 Jan 16, 2025
47d4dc8
GS/HW: Further fixes to HW renderer behaviour
refractionpcsx2 Jan 17, 2025
818527e
GS/HW: Fix up shuffle behaviour and affected areas
refractionpcsx2 Jan 23, 2025
704696b
GS/HW: Further fixes and rewrite of AlignedRectTranslate
refractionpcsx2 Jan 24, 2025
aaca8b2
GS: Add CRC hack for Guitar Hero 3 to handle crowds
refractionpcsx2 Jan 24, 2025
6d66eb8
GS/HW: Remove no longer required CRCs
refractionpcsx2 Jan 24, 2025
21bf2d2
GS/HW: Don't update TBP on targets + make target src's temporary
refractionpcsx2 Jan 24, 2025
a43cb2b
GameDB: Adjust fixes for games affected by RT in RT
refractionpcsx2 Jan 25, 2025
34a0d50
GS/HW: Check all overlapping pages when clearing sources
refractionpcsx2 Jan 25, 2025
25338fb
GS/HW: Predict valid sizes based on repeated draws and scissor
refractionpcsx2 Jan 25, 2025
b372cd9
GameDB-GS/HW: Remove Battlefield 2 CRC hacks, add Tex Inside RT instead
refractionpcsx2 Jan 25, 2025
07c87e3
GS/HW: Allow offsetting in to a target if full contained.
refractionpcsx2 Jan 26, 2025
14a9a5f
GS/HW: Intercept excessively large clears
refractionpcsx2 Jan 30, 2025
5ecac0d
GS/HW: Don't allow Tex in RT if not contained
refractionpcsx2 Jan 30, 2025
031f724
GS: Code cleanup at the behest of Const-Man
refractionpcsx2 Jan 30, 2025
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
291 changes: 189 additions & 102 deletions bin/resources/GameIndex.yaml

Large diffs are not rendered by default.

7 changes: 2 additions & 5 deletions bin/resources/shaders/dx11/tfx.fx
Original file line number Diff line number Diff line change
Expand Up @@ -1123,11 +1123,8 @@ PS_OUTPUT ps_main(PS_INPUT input)
{
if (PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
{
C.rb = C.br;
float g_temp = C.g;

C.g = C.a;
C.a = g_temp;
C.br = C.rb;
C.ag = C.ga;
}
else if(PS_PROCESS_BA & SHUFFLE_READ)
{
Expand Down
7 changes: 2 additions & 5 deletions bin/resources/shaders/opengl/tfx_fs.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -1086,11 +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.rb = C.br;
float g_temp = C.g;

C.g = C.a;
C.a = g_temp;
C.br = C.rb;
C.ag = C.ga;
#elif(PS_PROCESS_BA & SHUFFLE_READ)
C.rb = C.bb;
C.ga = C.aa;
Expand Down
11 changes: 4 additions & 7 deletions bin/resources/shaders/vulkan/tfx.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -945,7 +945,7 @@ vec4 ps_color()
vec4 T = sample_color(st);
#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);
#if (PS_PROCESS_BA & SHUFFLE_READ)
T.r = float((denorm_c_before.b << 3) & 0xF8u);
Expand Down Expand Up @@ -1320,7 +1320,7 @@ void main()
ps_blend(C, alpha_blend);

#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);
#if (PS_PROCESS_BA & SHUFFLE_READ)
C.b = float(((denorm_c_after.r >> 3) & 0x1Fu) | ((denorm_c_after.g << 2) & 0xE0u));
Expand Down Expand Up @@ -1350,11 +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.rb = C.br;
float g_temp = C.g;

C.g = C.a;
C.a = g_temp;
C.br = C.rb;
C.ag = C.ga;
#elif(PS_PROCESS_BA & SHUFFLE_READ)
C.rb = C.bb;
C.ga = C.aa;
Expand Down
77 changes: 68 additions & 9 deletions pcsx2/GS/GSState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ GSState::~GSState()
_aligned_free(m_vertex.buff);
if (m_index.buff)
_aligned_free(m_index.buff);
if (m_draw_vertex.buff)
_aligned_free(m_draw_vertex.buff);
if (m_draw_index.buff)
_aligned_free(m_draw_index.buff);
}

std::string GSState::GetDrawDumpPath(const char* format, ...)
Expand Down Expand Up @@ -467,7 +471,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.G) << 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;
}

Expand Down Expand Up @@ -849,7 +854,7 @@ void GSState::ApplyTEX0(GIFRegTEX0& TEX0)
// Urban Chaos writes to the memory backing the CLUT in the middle of a shuffle, and
// it's unclear whether the CLUT would actually get reloaded in that case.
if (TEX0.CBP != m_mem.m_clut.GetCLUTCBP())
m_channel_shuffle = false;
m_channel_shuffle_abort = true;
}

TEX0.CPSM &= 0xa; // 1010b
Expand Down Expand Up @@ -1674,7 +1679,8 @@ void GSState::FlushPrim()
Console.Warning("GS: Possible invalid draw, Frame PSM %x ZPSM %x", m_context->FRAME.PSM, m_context->ZBUF.PSM);
}
#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));

// Texel coordinate rounding
Expand Down Expand Up @@ -2794,8 +2800,10 @@ void GSState::GrowVertexBuffer()
const u32 maxcount = std::max<u32>(m_vertex.maxcount * 3 / 2, 10000);

GSVertex* vertex = static_cast<GSVertex*>(_aligned_malloc(sizeof(GSVertex) * maxcount, 32));
GSVertex* draw_vertex = static_cast<GSVertex*>(_aligned_malloc(sizeof(GSVertex) * maxcount, 32));
// Worst case index list is a list of points with vs expansion, 6 indices per point
u16* index = static_cast<u16*>(_aligned_malloc(sizeof(u16) * maxcount * 6, 32));
u16* draw_index = static_cast<u16*>(_aligned_malloc(sizeof(u16) * maxcount * 6, 32));

if (!vertex || !index)
{
Expand All @@ -2821,6 +2829,22 @@ void GSState::GrowVertexBuffer()
_aligned_free(m_index.buff);
}

if (m_draw_vertex.buff)
{
std::memcpy(draw_vertex, m_draw_vertex.buff, sizeof(GSVertex) * m_vertex.tail);

_aligned_free(m_draw_vertex.buff);
}

if (m_draw_index.buff)
{
std::memcpy(draw_index, m_draw_index.buff, sizeof(u16) * m_index.tail);

_aligned_free(m_draw_index.buff);
}

m_draw_vertex.buff = draw_vertex;
m_draw_index.buff = draw_index;
m_vertex.buff = vertex;
m_vertex.maxcount = maxcount - 3; // -3 to have some space at the end of the buffer before DrawingKick can grow it
m_index.buff = index;
Expand Down Expand Up @@ -3094,6 +3118,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))))
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 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.
Expand Down Expand Up @@ -3859,7 +3893,8 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
const GSVector2 grad(uv_range / pos_range);
// Adjust texture range when sprites get scissor clipped. Since we linearly interpolate, this
// 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_primitive_covers_without_gaps != NoGapsType::GapsFound && (m_vt.m_primclass == GS_SPRITE_CLASS || (m_vt.m_primclass == GS_TRIANGLE_CLASS && grad.x == 1.0f && grad.y == 1.0f && TrianglesAreQuads(false))))
{
// When coordinates are fractional, GS appears to draw to the right/bottom (effectively
// taking the ceiling), not to the top/left (taking the floor).
Expand All @@ -3870,11 +3905,24 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL

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_third = &m_vertex.buff[m_index.buff[2]];

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
const bool u_forward = vert_first->U < vert_second->U;
const bool x_forward = vert_first->XYZ.X < vert_second->XYZ.X;
const bool u_forward = u_forward_check;
const bool x_forward = x_forward_check;
const bool swap_x = u_forward != x_forward;

if (int_rc.left < scissored_rc.left)
Expand All @@ -3897,9 +3945,20 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
st.x = new_st.x;
st.z = new_st.z;
}

const bool v_forward = vert_first->V < vert_second->V;
const bool y_forward = vert_first->XYZ.Y < vert_second->XYZ.Y;
bool v_forward_check = false;
bool y_forward_check = false;
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;

if (int_rc.top < scissored_rc.top)
Expand Down
19 changes: 19 additions & 0 deletions pcsx2/GS/GSState.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,21 @@ class GSState : public GSAlignedClass<32>
u32 tail;
} m_index = {};

struct
{
GSVertex* buff;
u32 head, tail, next, maxcount; // head: first vertex, tail: last vertex + 1, next: last indexed + 1
u32 xy_tail;
GSVector4i xy[4];
GSVector4i xyhead;
} m_draw_vertex = {};

struct
{
u16* buff;
u32 tail;
} m_draw_index = {};

void UpdateContext();
void UpdateScissor();

Expand Down Expand Up @@ -224,6 +239,10 @@ class GSState : public GSAlignedClass<32>
bool m_texflush_flag = false;
bool m_isPackedUV_HackFlag = false;
bool m_channel_shuffle = false;
bool m_in_target_draw = false;
bool m_channel_shuffle_abort = false;

u32 m_target_offset = 0;
u8 m_scanmask_used = 0;
u32 m_dirty_gs_regs = 0;
int m_backed_up_ctx = 0;
Expand Down
5 changes: 5 additions & 0 deletions pcsx2/GS/GSVector4i.h
Original file line number Diff line number Diff line change
Expand Up @@ -1599,6 +1599,11 @@ class alignas(16) GSVector4i
return loadh(&v);
}

__forceinline static GSVector4i loadl(const GSVector2i& v)
{
return loadl(&v);
}

__forceinline static GSVector4i load(const void* pl, const void* ph)
{
return loadh(ph, loadl(pl));
Expand Down
Loading