GS: Read local memory without sync when readbacks are disabled

This commit is contained in:
Connor McLaughlin 2022-05-27 18:53:14 +10:00 committed by refractionpcsx2
parent 4fd06b5ea8
commit edd735ce80
8 changed files with 75 additions and 16 deletions

View File

@ -257,6 +257,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
connect(m_ui.enableHWFixes, &QCheckBox::stateChanged, this, &GraphicsSettingsWidget::onEnableHardwareFixesChanged);
updateRendererDependentOptions();
// only allow disabling readbacks for per-game settings, it's too dangerous
m_ui.disableHardwareReadbacks->setEnabled(m_dialog->isPerGameSettings());
dialog->registerWidgetHelp(m_ui.enableHWFixes, tr("Manual Hardware Renderer Fixes"), tr("Unchecked"),
tr("Enabling this option gives you the ability to change the renderer and upscaling fixes "
"to your games. However IF you have ENABLED this, you WILL DISABLE AUTOMATIC "
@ -271,6 +274,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
tr("Detects when idle frames are being presented in 25/30fps games, and skips presenting those frames. The frame is still rendered, it just means "
"the GPU has more time to complete it (this is NOT frame skipping). Can smooth our frame time fluctuations when the CPU/GPU are near maximum "
"utilization, but makes frame pacing more inconsistent and can increase input lag."));
dialog->registerWidgetHelp(m_ui.disableHardwareReadbacks, tr("Disable Hardware Readbacks"), tr("Unchecked"),
tr("Skips synchronizing with the GS thread and host GPU for GS downloads. "
"Can result in a large speed boost on slower systems, at the cost of many broken graphical effects. "
"If games are broken and you have this option enabled, please disable it first."));
}
GraphicsSettingsWidget::~GraphicsSettingsWidget() = default;

View File

@ -423,6 +423,11 @@ void GSInitAndReadFIFO(u8* mem, u32 size)
}
}
void GSReadLocalMemoryUnsync(u8* mem, u32 qwc, u64 BITBLITBUF, u64 TRXPOS, u64 TRXREG)
{
g_gs_renderer->ReadLocalMemoryUnsync(mem, qwc, GIFRegBITBLTBUF{BITBLITBUF}, GIFRegTRXPOS{TRXPOS}, GIFRegTRXREG{TRXREG});
}
void GSgifTransfer(const u8* mem, u32 size)
{
try

View File

@ -62,6 +62,7 @@ void GSclose();
void GSgifSoftReset(u32 mask);
void GSwriteCSR(u32 csr);
void GSInitAndReadFIFO(u8* mem, u32 size);
void GSReadLocalMemoryUnsync(u8* mem, u32 qwc, u64 BITBLITBUF, u64 TRXPOS, u64 TRXREG);
void GSgifTransfer(const u8* mem, u32 size);
void GSgifTransfer1(u8* mem, u32 addr);
void GSgifTransfer2(u8* mem, u32 size);

View File

@ -2091,6 +2091,25 @@ void GSState::ReadFIFO(u8* mem, int size)
m_dump->ReadFIFO(size);
}
void GSState::ReadLocalMemoryUnsync(u8* mem, int qwc, GIFRegBITBLTBUF BITBLTBUF, GIFRegTRXPOS TRXPOS, GIFRegTRXREG TRXREG)
{
const int sx = TRXPOS.SSAX;
const int sy = TRXPOS.SSAY;
const int w = TRXREG.RRW;
const int h = TRXREG.RRH;
const u16 bpp = GSLocalMemory::m_psm[BITBLTBUF.SPSM].trbpp;
GSTransferBuffer tb;
tb.Init(TRXPOS.SSAX, TRXPOS.SSAY, BITBLTBUF);
int len = qwc * 16;
if (!tb.Update(w, h, bpp, len))
return;
m_mem.ReadImageX(tb.x, tb.y, mem, len, BITBLTBUF, TRXPOS, TRXREG);
}
template void GSState::Transfer<0>(const u8* mem, u32 size);
template void GSState::Transfer<1>(const u8* mem, u32 size);
template void GSState::Transfer<2>(const u8* mem, u32 size);

View File

@ -322,6 +322,7 @@ public:
void SoftReset(u32 mask);
void WriteCSR(u32 csr) { m_regs->CSR.U32[1] = csr; }
void ReadFIFO(u8* mem, int size);
void ReadLocalMemoryUnsync(u8* mem, int qwc, GIFRegBITBLTBUF BITBLTBUF, GIFRegTRXPOS TRXPOS, GIFRegTRXREG TRXREG);
template<int index> void Transfer(const u8* mem, u32 size);
int Freeze(freezeData* fd, bool sizeonly);
int Defrost(const freezeData* fd);

View File

@ -27,15 +27,11 @@ bool Gif_HandlerAD(u8* pMem)
{
u32 reg = pMem[8];
u32* data = (u32*)pMem;
if (reg == 0x50)
if (reg >= GIF_A_D_REG_BITBLTBUF && reg <= GIF_A_D_REG_TRXREG)
{
vif1.BITBLTBUF._u64 = *(u64*)pMem;
vif1.transfer_registers[reg - GIF_A_D_REG_BITBLTBUF] = *(u64*)pMem;
}
else if (reg == 0x52)
{
vif1.TRXREG._u64 = *(u64*)pMem;
}
else if (reg == 0x53)
else if (reg == GIF_A_D_REG_TRXDIR)
{ // TRXDIR
if ((pMem[0] & 3) == 1)
{ // local -> host
@ -63,7 +59,7 @@ bool Gif_HandlerAD(u8* pMem)
vif1.GSLastDownloadSize = vif1.TRXREG.RRW * vif1.TRXREG.RRH * bpp >> 7;
}
}
else if (reg == 0x60)
else if (reg == GIF_A_D_REG_SIGNAL)
{ // SIGNAL
if (CSRreg.SIGNAL)
{ // Time to ignore all subsequent drawing operations.
@ -85,12 +81,12 @@ bool Gif_HandlerAD(u8* pMem)
CSRreg.SIGNAL = true;
}
}
else if (reg == 0x61)
else if (reg == GIF_A_D_REG_FINISH)
{ // FINISH
GUNIT_WARN("GIF Handler - FINISH");
CSRreg.FINISH = true;
}
else if (reg == 0x62)
else if (reg == GIF_A_D_REG_LABEL)
{ // LABEL
GUNIT_WARN("GIF Handler - LABEL");
GSSIGLBLID.LBLID = (GSSIGLBLID.LBLID & ~data[1]) | (data[0] & data[1]);
@ -108,7 +104,7 @@ bool Gif_HandlerAD_MTVU(u8* pMem)
u32 reg = pMem[8];
u32* data = (u32*)pMem;
if (reg == 0x60)
if (reg == GIF_A_D_REG_SIGNAL)
{ // SIGNAL
GUNIT_WARN("GIF Handler - SIGNAL");
if (vu1Thread.mtvuInterrupts.load(std::memory_order_acquire) & VU_Thread::InterruptFlagSignal)
@ -116,14 +112,14 @@ bool Gif_HandlerAD_MTVU(u8* pMem)
vu1Thread.gsSignal.store(((u64)data[1] << 32) | data[0], std::memory_order_relaxed);
vu1Thread.mtvuInterrupts.fetch_or(VU_Thread::InterruptFlagSignal, std::memory_order_release);
}
else if (reg == 0x61)
else if (reg == GIF_A_D_REG_FINISH)
{ // FINISH
GUNIT_WARN("GIF Handler - FINISH");
u32 old = vu1Thread.mtvuInterrupts.fetch_or(VU_Thread::InterruptFlagFinish, std::memory_order_relaxed);
if (old & VU_Thread::InterruptFlagFinish)
Console.Error("GIF Handler MTVU - Double FINISH Not Handled");
}
else if (reg == 0x62)
else if (reg == GIF_A_D_REG_LABEL)
{ // LABEL
GUNIT_WARN("GIF Handler - LABEL");
// It's okay to coalesce label updates

View File

@ -244,7 +244,10 @@ void SysMtgsThread::PostVsyncStart(bool registers_written)
void SysMtgsThread::InitAndReadFIFO(u8* mem, u32 qwc)
{
if (GSConfig.HWDisableReadbacks && GSConfig.UseHardwareRenderer())
{
GSReadLocalMemoryUnsync(mem, qwc, vif1.BITBLTBUF._u64, vif1.TRXPOS._u64, vif1.TRXREG._u64);
return;
}
SendPointerPacket(GS_RINGTYPE_INIT_AND_READ_FIFO, qwc, mem);
WaitGS(false, false, false);

View File

@ -44,9 +44,27 @@ union tBITBLTBUF {
};
};
union tTRXREG {
union tTRXPOS {
u64 _u64;
struct {
u32 SSAX : 11;
u32 _PAD1 : 5;
u32 SSAY : 11;
u32 _PAD2 : 5;
u32 DSAX : 11;
u32 _PAD3 : 5;
u32 DSAY : 11;
u32 DIRY : 1;
u32 DIRX : 1;
u32 _PAD4 : 3;
};
};
union tTRXREG
{
u64 _u64;
struct
{
u32 RRW : 12;
u32 _pad12 : 20;
u32 RRH : 12;
@ -83,8 +101,17 @@ struct vifStruct {
int unpackcalls;
// GS registers used for calculating the size of the last local->host transfer initiated on the GS
// Transfer size calculation should be restricted to GS emulation in the future
tBITBLTBUF BITBLTBUF;
tTRXREG TRXREG;
union
{
struct
{
tBITBLTBUF BITBLTBUF;
tTRXPOS TRXPOS;
tTRXREG TRXREG;
};
u64 transfer_registers[3];
};
u32 GSLastDownloadSize;
tVIF_CTRL irqoffset; // 32bit offset where next vif code is