mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-05-01 06:18:03 +03:00

1) What is the FIFO? The fifo is a ring queue for write (CPU) and read (GPU) the graphics commands. 2) What is the Brakpoints? The breakpoint is the FIFO mark to allow parallel work (CPU-GPU) When the GPU reached the breakpoint must stop read immediately until this Breakpoint will be removed for the CPU. 3) What is an overflow? The CPU write all room FIFO possible, and like a ring overwrite commands not processed yet. 4) ¿Why you have an overflow? In theory should not have an overflow never because the fifo has another mark (High Watermark) When the CPU Write reach this mark raise a CP interruption and the FIFO CPU WRITES should stop write until distance between READ POINTER AND WRITE POINTER will be equal to another mark (LO Watemark to prevent and overflow. 5) ¡So if impossible why you have overflows? Simple, the CP interruption is processed later and the Overflow happens. (there is a lot of theories about this) 6) ¿Why is no so simple like when CPU WRITE POINTER is near to the end of the FIFO only process pending graphics command? Because when this happens sometimes we are in BREAKPOINT and is IMPOSIBLE process the graphics commands. - This HACK process the pending data when CPU WRITE POINTER is 32 bytes before the end of the fifo, and if there is a Breakpoint force the situation to process the commands and prevent an overflown. In theory you have not see "FIFO is overflown by GatherPipe nCPU thread is too fast!" anymore. But if you have a hang in game where you had this please read the NOTICE LOG in user\logs, I've added this message "FIFO is almost in overflown, BreakPoint" when the hack is activated. (I will delete this message very soon) Good Luck!! PD: Shuffle sorry for the large commit description :P git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6662 8ced0084-cf51-0410-be5f-012b33b47a6e
216 lines
5.9 KiB
C++
216 lines
5.9 KiB
C++
// Copyright (C) 2003 Dolphin Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official SVN repository and contact information can be found at
|
|
// http://code.google.com/p/dolphin-emu/
|
|
|
|
#include "VideoConfig.h"
|
|
#include "Setup.h"
|
|
#include "MemoryUtil.h"
|
|
#include "Thread.h"
|
|
#include "Atomic.h"
|
|
#include "OpcodeDecoding.h"
|
|
#include "CommandProcessor.h"
|
|
#include "ChunkFile.h"
|
|
#include "Fifo.h"
|
|
|
|
volatile bool g_bSkipCurrentFrame = false;
|
|
volatile bool g_EFBAccessRequested = false;
|
|
extern u8* g_pVideoData;
|
|
|
|
namespace
|
|
{
|
|
static volatile bool fifoStateRun = false;
|
|
static volatile bool EmuRunning = false;
|
|
static u8 *videoBuffer;
|
|
static Common::EventEx fifo_run_event;
|
|
// STATE_TO_SAVE
|
|
static int size = 0;
|
|
} // namespace
|
|
|
|
void Fifo_DoState(PointerWrap &p)
|
|
{
|
|
CommandProcessor::FifoCriticalEnter();
|
|
|
|
p.DoArray(videoBuffer, FIFO_SIZE);
|
|
p.Do(size);
|
|
int pos = (int)(g_pVideoData - videoBuffer); // get offset
|
|
p.Do(pos); // read or write offset (depends on the mode afaik)
|
|
g_pVideoData = &videoBuffer[pos]; // overwrite g_pVideoData -> expected no change when load ss and change when save ss
|
|
|
|
CommandProcessor::FifoCriticalLeave();
|
|
}
|
|
|
|
void Fifo_Init()
|
|
{
|
|
videoBuffer = (u8*)AllocateMemoryPages(FIFO_SIZE);
|
|
fifo_run_event.Init();
|
|
fifoStateRun = false;
|
|
}
|
|
|
|
void Fifo_Shutdown()
|
|
{
|
|
if (fifoStateRun) PanicAlert("Fifo shutting down while active");
|
|
fifo_run_event.Shutdown();
|
|
FreeMemoryPages(videoBuffer, FIFO_SIZE);
|
|
}
|
|
|
|
u8* FAKE_GetFifoStartPtr()
|
|
{
|
|
return videoBuffer;
|
|
}
|
|
|
|
u8* FAKE_GetFifoEndPtr()
|
|
{
|
|
return &videoBuffer[size];
|
|
}
|
|
|
|
void Fifo_SetRendering(bool enabled)
|
|
{
|
|
g_bSkipCurrentFrame = !enabled;
|
|
}
|
|
|
|
// Executed from another thread, no the graphics thread!
|
|
// Basically, all it does is set a flag so that the loop will eventually exit, then
|
|
// waits for the event to be set, which happens when the loop does exit.
|
|
// If we look stuck in here, then the video thread is stuck in something and won't exit
|
|
// the loop. Switch to the video thread and investigate.
|
|
void Fifo_ExitLoop()
|
|
{
|
|
Fifo_ExitLoopNonBlocking();
|
|
}
|
|
|
|
// May be executed from any thread, even the graphics thread.
|
|
// Created to allow for self shutdown.
|
|
void Fifo_ExitLoopNonBlocking()
|
|
{
|
|
// This should break the wait loop in CPU thread
|
|
CommandProcessor::fifo.bFF_GPReadEnable = false;
|
|
CommandProcessor::SetFifoIdleFromVideoPlugin();
|
|
// Terminate GPU thread loop
|
|
fifoStateRun = false;
|
|
fifo_run_event.Set();
|
|
}
|
|
|
|
void Fifo_RunLoop(bool run)
|
|
{
|
|
EmuRunning = run;
|
|
if (run)
|
|
fifo_run_event.Set();
|
|
}
|
|
|
|
// Description: Fifo_EnterLoop() sends data through this function.
|
|
void Fifo_SendFifoData(u8* _uData, u32 len)
|
|
{
|
|
if (size + len >= FIFO_SIZE)
|
|
{
|
|
int pos = (int)(g_pVideoData - videoBuffer);
|
|
size -= pos;
|
|
if (size + len > FIFO_SIZE)
|
|
{
|
|
PanicAlert("FIFO out of bounds (sz = %i, at %08x)", size, pos);
|
|
}
|
|
memmove(&videoBuffer[0], &videoBuffer[pos], size);
|
|
g_pVideoData = videoBuffer;
|
|
}
|
|
// Copy new video instructions to videoBuffer for future use in rendering the new picture
|
|
memcpy(videoBuffer + size, _uData, len);
|
|
size += len;
|
|
}
|
|
|
|
|
|
// Description: Main FIFO update loop
|
|
// Purpose: Keep the Core HW updated about the CPU-GPU distance
|
|
void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|
{
|
|
|
|
fifoStateRun = true;
|
|
SCPFifoStruct &_fifo = CommandProcessor::fifo;
|
|
s32 distToSend;
|
|
|
|
while (fifoStateRun)
|
|
{
|
|
video_initialize.pPeekMessages();
|
|
|
|
VideoFifo_CheckAsyncRequest();
|
|
|
|
// check if we are able to run this buffer
|
|
|
|
CommandProcessor::SetStatus();
|
|
|
|
while (!CommandProcessor::interruptWaiting && _fifo.bFF_GPReadEnable &&
|
|
(_fifo.CPReadWriteDistance && !AtBreakpoint() || CommandProcessor::OnOverflow))
|
|
{
|
|
// while the FIFO is processing data we activate this for sync with emulator thread.
|
|
|
|
|
|
if (!fifoStateRun) break;
|
|
|
|
|
|
CommandProcessor::FifoCriticalEnter();
|
|
// Create pointer to video data and send it to the VideoPlugin
|
|
u32 readPtr = _fifo.CPReadPointer;
|
|
u8 *uData = video_initialize.pGetMemoryPointer(readPtr);
|
|
|
|
distToSend = 32;
|
|
|
|
if (readPtr == _fifo.CPEnd)
|
|
readPtr = _fifo.CPBase;
|
|
else
|
|
readPtr += 32;
|
|
|
|
_assert_msg_(COMMANDPROCESSOR, (s32)_fifo.CPReadWriteDistance - distToSend >= 0 ,
|
|
"Negative fifo.CPReadWriteDistance = %i in FIFO Loop !\nThat can produce inestabilty in the game. Please report it.", _fifo.CPReadWriteDistance - distToSend);
|
|
|
|
|
|
// Execute new instructions found in uData
|
|
Fifo_SendFifoData(uData, distToSend);
|
|
Common::AtomicStore(_fifo.CPReadPointer, readPtr);
|
|
Common::AtomicAdd(_fifo.CPReadWriteDistance, -distToSend);
|
|
|
|
CommandProcessor::isFifoBusy = true;
|
|
CommandProcessor::SetStatus();
|
|
|
|
_fifo.CPCmdIdle = false;
|
|
|
|
OpcodeDecoder_Run(g_bSkipCurrentFrame);
|
|
|
|
_fifo.CPCmdIdle = true;
|
|
|
|
CommandProcessor::isFifoBusy = false;
|
|
CommandProcessor::FifoCriticalLeave();
|
|
|
|
// Those two are pretty important and must be called in the FIFO Loop.
|
|
// If we don't, s_swapRequested (OGL only) or s_efbAccessRequested won't be set to false
|
|
// leading the CPU thread to wait in Video_BeginField or Video_AccessEFB thus slowing things down.
|
|
|
|
VideoFifo_CheckAsyncRequest();
|
|
|
|
}
|
|
|
|
|
|
CommandProcessor::SetFifoIdleFromVideoPlugin();
|
|
if (EmuRunning)
|
|
Common::YieldCPU();
|
|
else
|
|
fifo_run_event.MsgWait();
|
|
}
|
|
}
|
|
|
|
|
|
bool AtBreakpoint()
|
|
{
|
|
SCPFifoStruct &_fifo = CommandProcessor::fifo;
|
|
return _fifo.bFF_BPEnable && (_fifo.CPReadPointer == _fifo.CPBreakpoint);
|
|
}
|