mirror of
https://github.com/izzy2lost/Super3.git
synced 2026-07-05 15:18:38 -07:00
Fix flickering and other graphics
This commit is contained in:
+32
-21
@@ -1772,7 +1772,10 @@ void CModel3::Write32(UINT32 addr, UINT32 data)
|
||||
}
|
||||
else if ((addr>=0xF1180000) && (addr<0xF1180100))
|
||||
{
|
||||
TileGen.WriteRegister(addr&0xFF,FLIPENDIAN32(data));
|
||||
UINT32 flipped = FLIPENDIAN32(data);
|
||||
TileGen.WriteRegister(addr&0xFF, flipped);
|
||||
if (addr == 0xF118000C)
|
||||
GPU.TilegenDrawFrame(flipped);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2048,19 +2051,9 @@ void CModel3::RunMainBoardFrame(void)
|
||||
// Compute display and VBlank timings
|
||||
unsigned ppcCycles = m_config["PowerPCFrequency"].ValueAs<unsigned>() * 1000000;
|
||||
unsigned frameCycles = (unsigned)((float)ppcCycles / 57.524160f);
|
||||
unsigned gapCycles = (unsigned)((float)frameCycles * 2.5f / 100.0f); // we need a gap between asserting irq2 & irq 0x40
|
||||
unsigned offsetCycles = (unsigned)((float)frameCycles * 33.f / 100.0f);
|
||||
unsigned dispCycles = frameCycles - gapCycles - offsetCycles;
|
||||
unsigned statusCycles = (unsigned)((float)frameCycles * (0.005f));
|
||||
|
||||
// we think a frame looks like this on the model 2
|
||||
// 66% of frame
|
||||
// [irq2------------------ping_pong_flips------]
|
||||
//
|
||||
// Games will start writing a new frame at the ping_pong time. It could be the buffer swaps here.
|
||||
// Need more h/w testing to confirm.
|
||||
// What we are doing here is asserting IRQ2 at 33% of the frame, and treating the ping_pong flip as the front/back buffer swap
|
||||
// This way the data for the correct frames, ends up in the right frames!
|
||||
unsigned lineCycles = frameCycles / 424;
|
||||
unsigned vBlankCycles = lineCycles * 40;
|
||||
unsigned dispCycles = lineCycles * 384;
|
||||
|
||||
// Scale PPC timer ratio according to speed at which the PowerPC is being emulated so that the observed running frequency of the PPC timer
|
||||
// registers is more or less correct. This is needed to get the Virtua Striker 2 series of games running at the right speed (they are
|
||||
@@ -2072,11 +2065,8 @@ void CModel3::RunMainBoardFrame(void)
|
||||
if (gpusReady)
|
||||
{
|
||||
TileGen.BeginVBlank();
|
||||
GPU.BeginVBlank(statusCycles); // Games poll the ping_pong at startup. Values aren't 100% accurate so we stretch the frame a bit to ensure writes happen in the correct frame
|
||||
|
||||
ppc_execute(offsetCycles);
|
||||
IRQ.Assert(0x02); // start at 33% of the frame
|
||||
ppc_execute(gapCycles); // need a gap between asserting irqs
|
||||
GPU.BeginVBlank();
|
||||
ppc_execute(vBlankCycles);
|
||||
|
||||
/*
|
||||
* Sound:
|
||||
@@ -2100,7 +2090,10 @@ void CModel3::RunMainBoardFrame(void)
|
||||
// Process MIDI interrupt
|
||||
IRQ.Assert(0x40);
|
||||
ppc_execute(500); // give PowerPC time to acknowledge IR
|
||||
dispCycles -= 500;
|
||||
if (dispCycles >= 500)
|
||||
dispCycles -= 500;
|
||||
else
|
||||
dispCycles = 0;
|
||||
|
||||
++irqCount;
|
||||
if (irqCount > 128)
|
||||
@@ -2117,7 +2110,25 @@ void CModel3::RunMainBoardFrame(void)
|
||||
}
|
||||
|
||||
// Run the PowerPC for the active display part of the frame
|
||||
ppc_execute(dispCycles);
|
||||
unsigned pingPongFlipLine = TileGen.ReadRegister(0x08);
|
||||
for (unsigned i = 0; i < 384; i++)
|
||||
{
|
||||
if (i == pingPongFlipLine)
|
||||
GPU.FlipPingPongBit();
|
||||
|
||||
if (i == 383)
|
||||
IRQ.Assert(0x02);
|
||||
|
||||
unsigned cycles = lineCycles;
|
||||
if (dispCycles < cycles)
|
||||
cycles = dispCycles;
|
||||
|
||||
if (cycles > 0)
|
||||
ppc_execute(cycles);
|
||||
|
||||
if (dispCycles >= cycles)
|
||||
dispCycles -= cycles;
|
||||
}
|
||||
|
||||
timings.ppcTicks = CThread::GetTicks() - start;
|
||||
}
|
||||
|
||||
+63
-27
@@ -140,6 +140,8 @@ void CReal3D::LoadState(CBlockFile *SaveState)
|
||||
UpdateRenderConfig(Render3D, m_internalRenderConfig);
|
||||
SaveState->Read(&commandPortWritten);
|
||||
SaveState->Read(&m_pingPong, sizeof(m_pingPong));
|
||||
m_pingPongCopy = m_pingPong;
|
||||
m_tilegenDrawFrame = false;
|
||||
for (int i = 0; i < 39; i++)
|
||||
{
|
||||
uint8_t nul;
|
||||
@@ -162,13 +164,15 @@ static void UpdateRenderConfig(IRender3D *Render3D, uint64_t internalRenderConfi
|
||||
Render3D->SetSignedShade(shadeIsSigned);
|
||||
}
|
||||
|
||||
void CReal3D::BeginVBlank(int statusCycles)
|
||||
void CReal3D::BeginVBlank(void)
|
||||
{
|
||||
// Calculate point at which status bit should change value. Currently the same timing is used for both the status bit in ReadRegister
|
||||
// and in WriteDMARegister32/ReadDMARegister32, however it may be that they are completely unrelated. It appears that step 1.x games
|
||||
// access just the former while step 2.x access the latter. It is not known yet what this bit/these bits actually represent.
|
||||
statusChange = ppc_total_cycles() + statusCycles;
|
||||
m_evenFrame = !m_evenFrame;
|
||||
m_pingPongCopy = m_pingPong;
|
||||
|
||||
if (commandPortWritten)
|
||||
FlushTextures();
|
||||
|
||||
if (m_tilegenDrawFrame && commandPortWritten)
|
||||
DrawFrame();
|
||||
}
|
||||
|
||||
void CReal3D::EndVBlank(void)
|
||||
@@ -176,12 +180,15 @@ void CReal3D::EndVBlank(void)
|
||||
error = false; // clear error (just needs to be done once per frame)
|
||||
}
|
||||
|
||||
void CReal3D::FlipPingPongBit(void)
|
||||
{
|
||||
m_pingPong = !m_pingPong;
|
||||
m_tilegenDrawFrame = false;
|
||||
commandPortWritten = false;
|
||||
}
|
||||
|
||||
uint32_t CReal3D::SyncSnapshots(void)
|
||||
{
|
||||
// Update read-only copy of command port flag
|
||||
commandPortWrittenRO = commandPortWritten;
|
||||
commandPortWritten = false;
|
||||
|
||||
if (!m_gpuMultiThreaded)
|
||||
return 0;
|
||||
|
||||
@@ -268,8 +275,7 @@ void CReal3D::BeginFrame(void)
|
||||
|
||||
void CReal3D::RenderFrame(void)
|
||||
{
|
||||
//if (commandPortWrittenRO)
|
||||
Render3D->RenderFrame();
|
||||
Render3D->RenderFrame();
|
||||
}
|
||||
|
||||
void CReal3D::EndFrame(void)
|
||||
@@ -641,11 +647,8 @@ void CReal3D::WriteDMARegister32(unsigned reg, uint32_t data)
|
||||
Basic Emulation Functions, Registers, Memory, and Texture FIFO
|
||||
******************************************************************************/
|
||||
|
||||
void CReal3D::Flush(void)
|
||||
void CReal3D::FlushTextures()
|
||||
{
|
||||
commandPortWritten = true;
|
||||
DebugLog("Real3D 88000000 written @ PC=%08X\n", ppc_get_pc());
|
||||
|
||||
// Upload textures (if any)
|
||||
if (fifoIdx > 0)
|
||||
{
|
||||
@@ -673,6 +676,42 @@ void CReal3D::Flush(void)
|
||||
fifoIdx = 0;
|
||||
}
|
||||
|
||||
bool CReal3D::PollPingPong()
|
||||
{
|
||||
return m_pingPong != m_pingPongCopy;
|
||||
}
|
||||
|
||||
void CReal3D::DrawFrame()
|
||||
{
|
||||
m_tilegenDrawFrame = false;
|
||||
commandPortWritten = false;
|
||||
}
|
||||
|
||||
void CReal3D::TilegenDrawFrame(uint32_t flags)
|
||||
{
|
||||
(void)flags;
|
||||
m_tilegenDrawFrame = true;
|
||||
|
||||
if (!PollPingPong())
|
||||
{
|
||||
if (commandPortWritten)
|
||||
DrawFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void CReal3D::Flush(void)
|
||||
{
|
||||
commandPortWritten = true;
|
||||
DebugLog("Real3D 88000000 written @ PC=%08X\n", ppc_get_pc());
|
||||
|
||||
if (!PollPingPong())
|
||||
{
|
||||
FlushTextures();
|
||||
if (m_tilegenDrawFrame)
|
||||
DrawFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void CReal3D::WriteTextureFIFO(uint32_t data)
|
||||
{
|
||||
if (fifoIdx >= (0x100000/4))
|
||||
@@ -789,16 +828,8 @@ uint32_t CReal3D::ReadRegister(unsigned reg)
|
||||
DebugLog("Real3D: Read reg %X\n", reg);
|
||||
if (reg == 0)
|
||||
{
|
||||
uint32_t ping_pong;
|
||||
|
||||
if (m_evenFrame) {
|
||||
ping_pong = (ppc_total_cycles() >= statusChange ? 0x0 : 0x02000000);
|
||||
}
|
||||
else {
|
||||
ping_pong = (ppc_total_cycles() >= statusChange ? 0x02000000 : 0x0);
|
||||
}
|
||||
|
||||
return 0xfdffffff | ping_pong;
|
||||
uint32_t ping_pong = (m_pingPong ? 0x02000000 : 0x0);
|
||||
return 0xfdffffff | ping_pong;
|
||||
}
|
||||
|
||||
else if (reg >= 20 && reg<=32) { // line of sight registers
|
||||
@@ -867,8 +898,9 @@ void CReal3D::Reset(void)
|
||||
error = false;
|
||||
|
||||
m_pingPong = 0;
|
||||
m_pingPongCopy = 0;
|
||||
commandPortWritten = false;
|
||||
commandPortWrittenRO = false;
|
||||
m_tilegenDrawFrame = false;
|
||||
|
||||
queuedUploadTextures.clear();
|
||||
queuedUploadTexturesRO.clear();
|
||||
@@ -1029,6 +1061,10 @@ CReal3D::CReal3D(const Util::Config::Node &config)
|
||||
vrom = NULL;
|
||||
error = false;
|
||||
fifoIdx = 0;
|
||||
commandPortWritten = false;
|
||||
m_tilegenDrawFrame = false;
|
||||
m_pingPong = 0;
|
||||
m_pingPongCopy = 0;
|
||||
m_vromTextureFIFO[0] = 0;
|
||||
m_vromTextureFIFO[1] = 0;
|
||||
m_vromTextureFIFOIdx = 0;
|
||||
|
||||
+21
-4
@@ -121,7 +121,7 @@ public:
|
||||
*
|
||||
* Must be called before the VBlank starts.
|
||||
*/
|
||||
void BeginVBlank(int statusCycles);
|
||||
void BeginVBlank(void);
|
||||
|
||||
/*
|
||||
* EndVBlank(void)
|
||||
@@ -130,6 +130,13 @@ public:
|
||||
*/
|
||||
void EndVBlank(void);
|
||||
|
||||
/*
|
||||
* FlipPingPongBit(void)
|
||||
*
|
||||
* Any writes that happen after the ping_pong bit flips but before VBlank are buffered.
|
||||
*/
|
||||
void FlipPingPongBit(void);
|
||||
|
||||
/*
|
||||
* SyncSnapshots(void):
|
||||
*
|
||||
@@ -338,6 +345,14 @@ public:
|
||||
* data Data.
|
||||
*/
|
||||
void WritePCIConfigSpace(unsigned device, unsigned reg, unsigned bits, unsigned width, uint32_t data);
|
||||
|
||||
/*
|
||||
* TilegenDrawFrame(flags):
|
||||
*
|
||||
* The tilegen controls the frame timing. A write to reg 0x0C appears to
|
||||
* trigger the 3D hardware to draw the frame.
|
||||
*/
|
||||
void TilegenDrawFrame(uint32_t flags);
|
||||
|
||||
/*
|
||||
* Reset(void):
|
||||
@@ -436,6 +451,9 @@ private:
|
||||
void UploadTexture(uint32_t header, const uint16_t *texData);
|
||||
uint32_t UpdateSnapshots(bool copyWhole);
|
||||
uint32_t UpdateSnapshot(bool copyWhole, uint8_t *src, uint8_t *dst, unsigned size, uint8_t *dirty);
|
||||
void FlushTextures();
|
||||
bool PollPingPong();
|
||||
void DrawFrame();
|
||||
|
||||
// Config
|
||||
const Util::Config::Node &m_config;
|
||||
@@ -497,12 +515,11 @@ private:
|
||||
|
||||
// Command port
|
||||
bool commandPortWritten;
|
||||
bool commandPortWrittenRO; // Read-only copy of flag
|
||||
bool m_tilegenDrawFrame;
|
||||
|
||||
// Status and command registers
|
||||
uint32_t m_pingPong;
|
||||
uint64_t statusChange = 0;
|
||||
bool m_evenFrame = false;
|
||||
uint32_t m_pingPongCopy;
|
||||
|
||||
// Internal ASIC state
|
||||
std::unordered_map<ASIC, uint32_t> m_asicID;
|
||||
|
||||
@@ -326,6 +326,7 @@ struct Super3Host {
|
||||
|
||||
// Keep unsupported rendering knobs clamped on Android.
|
||||
config.Set("QuadRendering", false);
|
||||
config.Set("New3DEngine", true);
|
||||
config.Set("New3DAccurate", false);
|
||||
|
||||
// Allow user-specified framebuffer sizes. Clamp to sane bounds so we don't
|
||||
|
||||
Reference in New Issue
Block a user