GS: Retool downloads to buffer full read

This commit is contained in:
refractionpcsx2 2023-04-07 03:25:09 +01:00
parent f2229a0007
commit d4c3501bb8
4 changed files with 81 additions and 57 deletions

View File

@ -460,7 +460,7 @@ public:
typedef u32 (GSLocalMemory::*readPixelAddr)(u32 addr) const; typedef u32 (GSLocalMemory::*readPixelAddr)(u32 addr) const;
typedef u32 (GSLocalMemory::*readTexelAddr)(u32 addr, const GIFRegTEXA& TEXA) const; typedef u32 (GSLocalMemory::*readTexelAddr)(u32 addr, const GIFRegTEXA& TEXA) const;
typedef void (*writeImage)(GSLocalMemory& mem, int& tx, int& ty, const u8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); typedef void (*writeImage)(GSLocalMemory& mem, int& tx, int& ty, const u8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG);
typedef void (*readImage)(const GSLocalMemory& mem, int& tx, int& ty, int& offset, u8* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); typedef void (*readImage)(const GSLocalMemory& mem, int& tx, int& ty, u8* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG);
typedef void (*readTexture)(GSLocalMemory& mem, const GSOffset& off, const GSVector4i& r, u8* dst, int dstpitch, const GIFRegTEXA& TEXA); typedef void (*readTexture)(GSLocalMemory& mem, const GSOffset& off, const GSVector4i& r, u8* dst, int dstpitch, const GIFRegTEXA& TEXA);
typedef void (*readTextureBlock)(const GSLocalMemory& mem, u32 bp, u8* dst, int dstpitch, const GIFRegTEXA& TEXA); typedef void (*readTextureBlock)(const GSLocalMemory& mem, u32 bp, u8* dst, int dstpitch, const GIFRegTEXA& TEXA);
@ -1124,9 +1124,9 @@ public:
return ReadTexel16(PixelAddress16SZ(x, y, TEX0.TBP0, TEX0.TBW), TEXA); return ReadTexel16(PixelAddress16SZ(x, y, TEX0.TBP0, TEX0.TBW), TEXA);
} }
__forceinline void ReadImageX(int& tx, int& ty, int& offset, u8* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) const __forceinline void ReadImageX(int& tx, int& ty, u8* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) const
{ {
m_readImageX(*this, tx, ty, offset, dst, len, BITBLTBUF, TRXPOS, TRXREG); m_readImageX(*this, tx, ty, dst, len, BITBLTBUF, TRXPOS, TRXREG);
} }
void ReadTexture(const GSOffset& off, const GSVector4i& r, u8* dst, int dstpitch, const GIFRegTEXA& TEXA); void ReadTexture(const GSOffset& off, const GSVector4i& r, u8* dst, int dstpitch, const GIFRegTEXA& TEXA);

View File

@ -87,7 +87,7 @@ class CURRENT_ISA::GSLocalMemoryFunctions
static void ReadTexture(GSLocalMemory& mem, const GSOffset& off, const GSVector4i& r, u8* dst, int dstpitch, const GIFRegTEXA& TEXA); static void ReadTexture(GSLocalMemory& mem, const GSOffset& off, const GSVector4i& r, u8* dst, int dstpitch, const GIFRegTEXA& TEXA);
public: public:
static void ReadImageX(const GSLocalMemory& mem, int& tx, int& ty, int& offset, u8* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); static void ReadImageX(const GSLocalMemory& mem, int& tx, int& ty, u8* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG);
static void PopulateFunctions(GSLocalMemory& mem); static void PopulateFunctions(GSLocalMemory& mem);
}; };
@ -931,7 +931,7 @@ void GSLocalMemoryFunctions::WriteImageX(GSLocalMemory& mem, int& tx, int& ty, c
// //
void GSLocalMemoryFunctions::ReadImageX(const GSLocalMemory& mem, int& tx, int& ty, int& offset, u8* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) void GSLocalMemoryFunctions::ReadImageX(const GSLocalMemory& mem, int& tx, int& ty, u8* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG)
{ {
if (len <= 0) if (len <= 0)
return; return;
@ -1005,13 +1005,7 @@ void GSLocalMemoryFunctions::ReadImageX(const GSLocalMemory& mem, int& tx, int&
case PSMCT24: case PSMCT24:
case PSMZ24: case PSMZ24:
{ readWriteHelper(mem.vm32(), tx, ty, len / 3, 1, sx, w, off.assertSizesMatch(GSLocalMemory::swizzle32), [&](auto& pa, int x)
const int length = len / 3;
if ((length * 3) != len)
{
offset = (len - (length * 3));
}
readWriteHelper(mem.vm32(), tx, ty, length, 1, sx, w, off.assertSizesMatch(GSLocalMemory::swizzle32), [&](auto& pa, int x)
{ {
u32 c = *pa.value(x); u32 c = *pa.value(x);
pb[0] = (u8)(c); pb[0] = (u8)(c);
@ -1020,7 +1014,6 @@ void GSLocalMemoryFunctions::ReadImageX(const GSLocalMemory& mem, int& tx, int&
pb += 3; pb += 3;
}); });
break; break;
}
case PSMCT16: case PSMCT16:
case PSMCT16S: case PSMCT16S:
case PSMZ16: case PSMZ16:

View File

@ -106,6 +106,7 @@ GSState::GSState()
memset(&m_vertex, 0, sizeof(m_vertex)); memset(&m_vertex, 0, sizeof(m_vertex));
memset(&m_index, 0, sizeof(m_index)); memset(&m_index, 0, sizeof(m_index));
memset(m_mem.m_vm8, 0, m_mem.m_vmsize); memset(m_mem.m_vm8, 0, m_mem.m_vmsize);
m_v.RGBAQ.Q = 1.0f; m_v.RGBAQ.Q = 1.0f;
GrowVertexBuffer(); GrowVertexBuffer();
@ -1403,10 +1404,10 @@ void GSState::GIFRegHandlerTRXDIR(const GIFReg* RESTRICT r)
switch (m_env.TRXDIR.XDIR) switch (m_env.TRXDIR.XDIR)
{ {
case 0: // host -> local case 0: // host -> local
m_tr.Init(m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY, m_env.BITBLTBUF); m_tr.Init(m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY, m_env.BITBLTBUF, true);
break; break;
case 1: // local -> host case 1: // local -> host
m_tr.Init(m_env.TRXPOS.SSAX, m_env.TRXPOS.SSAY, m_env.BITBLTBUF); m_tr.Init(m_env.TRXPOS.SSAX, m_env.TRXPOS.SSAY, m_env.BITBLTBUF, false);
break; break;
case 2: // local -> local case 2: // local -> local
Move(); Move();
@ -1463,6 +1464,9 @@ void GSState::Flush(GSFlushReason reason)
void GSState::FlushWrite() void GSState::FlushWrite()
{ {
if (!m_tr.write)
return;
const int len = m_tr.end - m_tr.start; const int len = m_tr.end - m_tr.start;
if (len <= 0) if (len <= 0)
@ -1769,11 +1773,10 @@ void GSState::Write(const u8* mem, int len)
void GSState::InitReadFIFO(u8* mem, int len) void GSState::InitReadFIFO(u8* mem, int len)
{ {
if (len <= 0) // No size or already a transfer in progress.
if (len <= 0 || m_tr.total != 0)
return; return;
const int sx = m_env.TRXPOS.SSAX;
const int sy = m_env.TRXPOS.SSAY;
const int w = m_env.TRXREG.RRW; const int w = m_env.TRXREG.RRW;
const int h = m_env.TRXREG.RRH; const int h = m_env.TRXREG.RRH;
@ -1782,36 +1785,15 @@ void GSState::InitReadFIFO(u8* mem, int len)
if (!m_tr.Update(w, h, bpp, len)) if (!m_tr.Update(w, h, bpp, len))
return; return;
if (m_tr.x == sx && m_tr.y == sy)
InvalidateLocalMem(m_env.BITBLTBUF, GSVector4i(sx, sy, sx + w, sy + h));
}
// NOTE: called from outside MTGS
void GSState::Read(u8* mem, int len)
{
if (len <= 0)
return;
const int sx = m_env.TRXPOS.SSAX; const int sx = m_env.TRXPOS.SSAX;
const int sy = m_env.TRXPOS.SSAY; const int sy = m_env.TRXPOS.SSAY;
const int w = m_env.TRXREG.RRW;
const int h = m_env.TRXREG.RRH;
const GSVector4i r(sx, sy, sx + w, sy + h); const GSVector4i r(sx, sy, sx + w, sy + h);
const u16 bpp = GSLocalMemory::m_psm[m_env.BITBLTBUF.SPSM].trbpp; if (m_tr.x == sx && m_tr.y == sy)
InvalidateLocalMem(m_env.BITBLTBUF, r);
if (!m_tr.Update(w, h, bpp, len)) // Read the image all in one go.
return; m_mem.ReadImageX(m_tr.x, m_tr.y, m_tr.buff, m_tr.total, m_env.BITBLTBUF, m_env.TRXPOS, m_env.TRXREG);
// If it's 1 QW the destination is likely a register, so don't mess with this, else it can cause stack corruption.
// TODO: Change the FIFO downloads to just read off the whole transfer from memory to a temp buffer so we can read it in byte level chunks.
if (len > 16)
{
mem -= m_tr.offset;
len += m_tr.offset;
}
m_mem.ReadImageX(m_tr.x, m_tr.y, m_tr.offset, mem, len, m_env.BITBLTBUF, m_env.TRXPOS, m_env.TRXREG);
if (GSConfig.DumpGSData && GSConfig.SaveRT && s_n >= GSConfig.SaveN) if (GSConfig.DumpGSData && GSConfig.SaveRT && s_n >= GSConfig.SaveN)
{ {
@ -1824,6 +1806,36 @@ void GSState::Read(u8* mem, int len)
} }
} }
// NOTE: called from outside MTGS
void GSState::Read(u8* mem, int len)
{
if (len <= 0 || m_tr.total == 0)
return;
const int w = m_env.TRXREG.RRW;
const int h = m_env.TRXREG.RRH;
const u16 bpp = GSLocalMemory::m_psm[m_env.BITBLTBUF.SPSM].trbpp;
if (!m_tr.Update(w, h, bpp, len))
return;
// If it wraps memory, we need to break it up so we don't read out of bounds.
if ((m_tr.end + len) > m_mem.m_vmsize)
{
const int first_transfer = m_mem.m_vmsize - m_tr.end;
const int second_transfer = len - first_transfer;
memcpy(mem, &m_tr.buff[m_tr.end], first_transfer);
m_tr.end = 0;
memcpy(&mem[first_transfer], &m_tr.buff, second_transfer);
m_tr.end = second_transfer;
}
else
{
memcpy(mem, &m_tr.buff[m_tr.end], len);
m_tr.end += len;
}
}
void GSState::Move() void GSState::Move()
{ {
// ffxii uses this to move the top/bottom of the scrolling menus offscreen and then blends them back over the text to create a shading effect // ffxii uses this to move the top/bottom of the scrolling menus offscreen and then blends them back over the text to create a shading effect
@ -2096,15 +2108,34 @@ void GSState::ReadLocalMemoryUnsync(u8* mem, int qwc, GIFRegBITBLTBUF BITBLTBUF,
const u16 bpp = GSLocalMemory::m_psm[BITBLTBUF.SPSM].trbpp; const u16 bpp = GSLocalMemory::m_psm[BITBLTBUF.SPSM].trbpp;
GSTransferBuffer tb; GSTransferBuffer tb;
tb.Init(TRXPOS.SSAX, TRXPOS.SSAY, BITBLTBUF);
if(m_tr.end >= m_tr.total || m_tr.write == true)
tb.Init(TRXPOS.SSAX, TRXPOS.SSAY, BITBLTBUF, false);
int len = qwc * 16; int len = qwc * 16;
if (!tb.Update(w, h, bpp, len)) if (!tb.Update(w, h, bpp, len))
return; return;
mem += tb.offset; if (m_tr.start == 0)
len -= tb.offset; {
m_mem.ReadImageX(tb.x, tb.y, tb.offset, mem, len, BITBLTBUF, TRXPOS, TRXREG); m_mem.ReadImageX(tb.x, tb.y, m_tr.buff, m_tr.total, BITBLTBUF, TRXPOS, TRXREG);
m_tr.start += m_tr.total;
}
if ((m_tr.end + len) > m_mem.m_vmsize)
{
const int masked_end = m_tr.end & 0x3FFFFF; // 4mb.
const int first_transfer = m_mem.m_vmsize - masked_end;
const int second_transfer = len - first_transfer;
memcpy(mem, &m_tr.buff[masked_end], first_transfer);
memcpy(&mem[first_transfer], &m_tr.buff, second_transfer);
m_tr.end += len;
}
else
{
memcpy(mem, &m_tr.buff[m_tr.end], len);
m_tr.end += len;
}
} }
void GSState::PurgePool() void GSState::PurgePool()
@ -3862,13 +3893,13 @@ GSState::GSTransferBuffer::~GSTransferBuffer()
_aligned_free(buff); _aligned_free(buff);
} }
void GSState::GSTransferBuffer::Init(int tx, int ty, const GIFRegBITBLTBUF& blit) void GSState::GSTransferBuffer::Init(int tx, int ty, const GIFRegBITBLTBUF& blit, bool is_write)
{ {
x = tx; x = tx;
y = ty; y = ty;
total = 0; total = 0;
offset = 0;
m_blit = blit; m_blit = blit;
write = is_write;
} }
bool GSState::GSTransferBuffer::Update(int tw, int th, int bpp, int& len) bool GSState::GSTransferBuffer::Update(int tw, int th, int bpp, int& len)

View File

@ -123,14 +123,14 @@ private:
{ {
int x = 0, y = 0; int x = 0, y = 0;
int start = 0, end = 0, total = 0; int start = 0, end = 0, total = 0;
int offset = 0;
u8* buff = nullptr; u8* buff = nullptr;
GIFRegBITBLTBUF m_blit = {}; GIFRegBITBLTBUF m_blit = {};
bool write = false;
GSTransferBuffer(); GSTransferBuffer();
virtual ~GSTransferBuffer(); virtual ~GSTransferBuffer();
void Init(int tx, int ty, const GIFRegBITBLTBUF& blit); void Init(int tx, int ty, const GIFRegBITBLTBUF& blit, bool write);
bool Update(int tw, int th, int bpp, int& len); bool Update(int tw, int th, int bpp, int& len);
} m_tr; } m_tr;