mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-10-12 02:08:45 +00:00
GS:SW: Prepare DrawScanline for being more than 2GB from const data
This commit is contained in:
@@ -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 <typename A, typename B>
|
||||
static bool IsInRipRelativeRange(A* a, B* b)
|
||||
{
|
||||
uptr ai = reinterpret_cast<uptr>(a);
|
||||
uptr bi = reinterpret_cast<uptr>(b);
|
||||
sptr diff = static_cast<sptr>(bi - ai);
|
||||
return diff == static_cast<s32>(diff);
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
static s32 CalcOffset(A* from, B* to)
|
||||
{
|
||||
uptr ai = reinterpret_cast<uptr>(from);
|
||||
uptr bi = reinterpret_cast<uptr>(to);
|
||||
return static_cast<s32>(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<const void*>(static_cast<void (*)(int, int, int, const GSVertexSW&, GSScanlineLocalData&)>(
|
||||
&GSDrawScanline::CDrawScanline)));
|
||||
auto cds = static_cast<void(*)(int, int, int, const GSVertexSW&, GSScanlineLocalData&)>(&GSDrawScanline::CDrawScanline);
|
||||
if (IsInRipRelativeRange(actual.getCode(), cds))
|
||||
{
|
||||
jmp(reinterpret_cast<void*>(cds));
|
||||
}
|
||||
else
|
||||
{
|
||||
mov(rax, reinterpret_cast<uptr>(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<const char*>(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<uptr>(&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<uptr>(&g_const);
|
||||
#if USING_XMM
|
||||
uptr target = reinterpret_cast<uptr>(&g_const.m_log2_coef_128b[i]);
|
||||
#else
|
||||
uptr target = reinterpret_cast<uptr>(&g_const.m_log2_coef_256b[i]);
|
||||
#endif
|
||||
return static_cast<s32>(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));
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user