From 1160758a814597229cc6bf64fd931e74c75326c8 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sun, 6 Oct 2024 20:41:12 -0500 Subject: [PATCH] GS:SW: Prepare DrawScanline for being more than 2GB from const data --- .../SW/GSDrawScanlineCodeGenerator.all.cpp | 83 ++++++++++++++----- .../SW/GSDrawScanlineCodeGenerator.all.h | 9 +- 2 files changed, 68 insertions(+), 24 deletions(-) diff --git a/pcsx2/GS/Renderers/SW/GSDrawScanlineCodeGenerator.all.cpp b/pcsx2/GS/Renderers/SW/GSDrawScanlineCodeGenerator.all.cpp index 0add3da388..fd020c7817 100644 --- a/pcsx2/GS/Renderers/SW/GSDrawScanlineCodeGenerator.all.cpp +++ b/pcsx2/GS/Renderers/SW/GSDrawScanlineCodeGenerator.all.cpp @@ -16,7 +16,6 @@ using namespace Xbyak; #pragma clang diagnostic ignored "-Winvalid-offsetof" // We know what we're doing. #endif -#define _rip_const(cptr) ptr[rip + ((char*)(cptr))] #define _rip_local(field) ptr[_m_local + offsetof(GSScanlineLocalData, field)] #define _rip_local_offset(field, offset) ptr[_m_local + offsetof(GSScanlineLocalData, field) + (offset)] #define _rip_global(field) ptr[_m_local__gd + offsetof(GSScanlineGlobalData, field)] @@ -68,6 +67,23 @@ using namespace Xbyak; #define _rip_local_d_p(x) _rip_local_d(x) #endif +template +static bool IsInRipRelativeRange(A* a, B* b) +{ + uptr ai = reinterpret_cast(a); + uptr bi = reinterpret_cast(b); + sptr diff = static_cast(bi - ai); + return diff == static_cast(diff); +} + +template +static s32 CalcOffset(A* from, B* to) +{ + uptr ai = reinterpret_cast(from); + uptr bi = reinterpret_cast(to); + return static_cast(bi - ai); +} + GSDrawScanlineCodeGenerator::GSDrawScanlineCodeGenerator(u64 key, void* code, size_t maxsize) : GSNewCodeGenerator(code, maxsize) #ifdef _WIN32 @@ -83,6 +99,7 @@ GSDrawScanlineCodeGenerator::GSDrawScanlineCodeGenerator(u64 key, void* code, si , t2(rcx), t3(rsi) , _m_local(r8) #endif + , _m_const(r14) , _m_local__gd(r12) , _m_local__gd__vm(t3) , _m_local__gd__clut(r11) @@ -90,7 +107,7 @@ GSDrawScanlineCodeGenerator::GSDrawScanlineCodeGenerator(u64 key, void* code, si , _rb(xym5), _ga(xym6), _fm(xym3), _zm(xym4), _fd(xym2), _test(xym15) , _z(xym8), _f(xym9), _s(xym10), _t(xym11), _q(xym12), _f_rb(xym13), _f_ga(xym14) { - // Free: r14, r15, rbp, to use, remember to save them. + // Free: r15, rbp, to use, remember to save them. m_sel.key = key; use_lod = m_sel.mmin; if (isYmm) @@ -315,8 +332,16 @@ void GSDrawScanlineCodeGenerator::Generate() if (GSDrawScanline::ShouldUseCDrawScanline(m_sel.key)) { - jmp(reinterpret_cast(static_cast( - &GSDrawScanline::CDrawScanline))); + auto cds = static_cast(&GSDrawScanline::CDrawScanline); + if (IsInRipRelativeRange(actual.getCode(), cds)) + { + jmp(reinterpret_cast(cds)); + } + else + { + mov(rax, reinterpret_cast(cds)); + actual.jmp(ptr[rax]); + } return; } @@ -329,6 +354,7 @@ void GSDrawScanlineCodeGenerator::Generate() push(rdi); push(r12); push(r13); + push(r14); sub(rsp, _64_win_stack_size); @@ -340,14 +366,22 @@ void GSDrawScanlineCodeGenerator::Generate() mov(ptr[rsp + _64_rz_rbx], rbx); mov(ptr[rsp + _64_rz_r12], r12); mov(ptr[rsp + _64_rz_r13], r13); + mov(ptr[rsp + _64_rz_r14], r14); #endif #ifdef _WIN32 // Local (5th arg) is passed on the stack in Windows. - // 32 bytes shadow space less the 5 pushed registers and return address = 80. - mov(_m_local, ptr[rsp + _64_win_stack_size + 80]); + // 32 bytes shadow space less the 6 pushed registers and return address = 88. + mov(_m_local, ptr[rsp + _64_win_stack_size + 88]); #endif + const void* code = actual.getCode(); + const char* codeEnd = reinterpret_cast(code) + (1024 * 1024); + if (IsInRipRelativeRange(code, &g_const) && IsInRipRelativeRange(codeEnd, &g_const)) + lea(_m_const, ptr[rip + &g_const]); + else + mov(_m_const, reinterpret_cast(&g_const)); + mov(_m_local__gd, _rip_local(gd)); if (need_clut) @@ -577,6 +611,7 @@ L("exit"); } add(rsp, _64_win_stack_size); + pop(r14); pop(r13); pop(r12); pop(rdi); @@ -586,6 +621,7 @@ L("exit"); mov(rbx, ptr[rsp + _64_rz_rbx]); mov(r12, ptr[rsp + _64_rz_r12]); mov(r13, ptr[rsp + _64_rz_r13]); + mov(r14, ptr[rsp + _64_rz_r14]); #endif if (isYmm) vzeroupper(); @@ -623,16 +659,14 @@ void GSDrawScanlineCodeGenerator::Init() if (isXmm) { - lea(t1, _rip_const(&g_const.m_test_128b[0])); shl(a1.cvt32(), 4); // * sizeof(m_test[0]) - movdqa(_test, ptr[a1 + t1]); - por(_test, ptr[rax + t1 + (offsetof(GSScanlineConstantData, m_test_128b[7]) - offsetof(GSScanlineConstantData, m_test_128b[0]))]); + movdqa(_test, ptr[a1 + _m_const + offsetof(GSScanlineConstantData, m_test_128b[0])]); + por(_test, ptr[rax + _m_const + offsetof(GSScanlineConstantData, m_test_128b[7])]); } else { - lea(t1, _rip_const(&g_const.m_test_256b[0])); - pmovsxbd(_test, ptr[a1 * 8 + t1]); - pmovsxbd(xym0, ptr[rax * 8 + t1 + (offsetof(GSScanlineConstantData, m_test_256b[15]) - offsetof(GSScanlineConstantData, m_test_256b[0]))]); + pmovsxbd(_test, ptr[a1 * 8 + _m_const + offsetof(GSScanlineConstantData, m_test_256b[0])]); + pmovsxbd(xym0, ptr[rax * 8 + _m_const + offsetof(GSScanlineConstantData, m_test_256b[15])]); por(_test, xym0); shl(a1.cvt32(), 5); // * sizeof(m_test[0]) } @@ -1011,11 +1045,9 @@ void GSDrawScanlineCodeGenerator::Step() cdqe(); #if USING_XMM - lea(t2, _rip_const(&g_const.m_test_128b[7])); - movdqa(_test, ptr[rax + t2]); + movdqa(_test, ptr[rax + _m_const + offsetof(GSScanlineConstantData, m_test_128b[7])]); #else - lea(t2, _rip_const(&g_const.m_test_256b[15])); - pmovsxbd(_test, ptr[rax * 8 + t2]); + pmovsxbd(_test, ptr[rax * 8 + _m_const + offsetof(GSScanlineConstantData, m_test_256b[15])]); #endif } } @@ -1051,7 +1083,7 @@ void GSDrawScanlineCodeGenerator::TestZ(const XYm& temp1, const XYm& temp2) // zs = GSVector8i(zl, zh); // zs += VectorI::x80000000(); - broadcastsd(temp1, _rip_const(&GSVector4::m_xc1e00000000fffff)); + broadcastsd(temp1, ptr[_m_const + CalcOffset(&g_const, &GSVector4::m_xc1e00000000fffff)]); addpd(xym7, temp1); addpd(temp1, _z); @@ -1551,6 +1583,18 @@ void GSDrawScanlineCodeGenerator::Wrap(const XYm& uv0, const XYm& uv1) } } +static s32 log2_coeff_offset(int i) +{ + // Yay, you can't offsetof with non-constant array indices + uptr base = reinterpret_cast(&g_const); +#if USING_XMM + uptr target = reinterpret_cast(&g_const.m_log2_coef_128b[i]); +#else + uptr target = reinterpret_cast(&g_const.m_log2_coef_256b[i]); +#endif + return static_cast(target - base); +}; + /// Input[x86]: xym4=q, xym2=s, xym3=t /// Output: _rb, _ga /// Destroys everything except xym7[x86] @@ -1604,10 +1648,7 @@ void GSDrawScanlineCodeGenerator::SampleTextureLOD() auto log2_coeff = [this](int i) -> Address { - if (isXmm) - return _rip_const(&g_const.m_log2_coef_128b[i]); - else - return _rip_const(&g_const.m_log2_coef_256b[i]); + return ptr[_m_const + log2_coeff_offset(i)]; }; orps(xym4, log2_coeff(3)); diff --git a/pcsx2/GS/Renderers/SW/GSDrawScanlineCodeGenerator.all.h b/pcsx2/GS/Renderers/SW/GSDrawScanlineCodeGenerator.all.h index 0f32e9e221..8bb38c63e9 100644 --- a/pcsx2/GS/Renderers/SW/GSDrawScanlineCodeGenerator.all.h +++ b/pcsx2/GS/Renderers/SW/GSDrawScanlineCodeGenerator.all.h @@ -41,9 +41,12 @@ class GSDrawScanlineCodeGenerator : public GSNewCodeGenerator constexpr static int _64_top = 8 * 0; // XMM registers will be saved to `rsp + _64_win_xmm_start + id - 6` // Which will put xmm6 after the temporaries, them xmm7, etc - constexpr static int _64_win_xmm_start = 8 * 2; + constexpr static int _64_win_xmm_start = 8 * 1; + // Align the xmm variables on the stack with this + // Since we don't call any other functions, we don't need to keep rsp itself aligned + constexpr static int _64_win_xmm_align = 8 * 1; // Windows has no redzone and also has 10 xmm registers to save - constexpr static int _64_win_stack_size = _64_win_xmm_start + 16 * 10; + constexpr static int _64_win_stack_size = _64_win_xmm_align + _64_win_xmm_start + 16 * 10; #else // System-V has a redzone so stick everything there constexpr static int _64_rz_rbx = -8 * 1; @@ -62,7 +65,7 @@ class GSDrawScanlineCodeGenerator : public GSNewCodeGenerator /// Note: a2 and t3 are only available on x86-64 /// Outside of Init, usable registers are a0, t0, t1, t2, t3[x64], rax, rbx, rdx, r10+ const AddressReg a0, a1, a2, a3, t0, t1, t2, t3; - const AddressReg _m_local, _m_local__gd, _m_local__gd__vm, _m_local__gd__clut; + const AddressReg _m_local, _m_const, _m_local__gd, _m_local__gd__vm, _m_local__gd__clut; // If use_lod, m_local.gd->tex, else m_local.gd->tex[0] const AddressReg _m_local__gd__tex; /// Available on both x86 and x64, not always valid