mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-10 16:19:28 +01:00
35b6e71f03
Enable the thread by adding this line to the video plugin ini files, "User\Config\gfx_dx9.ini" and "User\Config\gfx_opengl.ini": UseFIFOThread = True The line should be added under the UseXFB line. To disable the FIFO thread, use this line: UseFIFOThread = False If the line is not in the ini file, the default is disabled (i.e. False). The FIFO thread causes an error when the OpenGL plugin is used. The D3D plugin works. Only top left quarter of the screen can be seen when rendering to main window. The entire screen can be viewed when running in a window. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4930 8ced0084-cf51-0410-be5f-012b33b47a6e
269 lines
7.1 KiB
C++
269 lines
7.1 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 <string.h>
|
|
|
|
#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
|
|
|
|
Common::Thread *g_hFifoThread = NULL;
|
|
SVideoInitialize video_initialize;
|
|
|
|
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);
|
|
if (size - pos > pos)
|
|
{
|
|
PanicAlert("FIFO out of bounds (sz = %i, at %08x)", size, pos);
|
|
}
|
|
memmove(&videoBuffer[0], &videoBuffer[pos], size - pos);
|
|
size -= pos;
|
|
g_pVideoData = videoBuffer;
|
|
}
|
|
// Copy new video instructions to videoBuffer for future use in rendering the new picture
|
|
memcpy(videoBuffer + size, _uData, len);
|
|
size += len;
|
|
OpcodeDecoder_Run(g_bSkipCurrentFrame);
|
|
}
|
|
|
|
inline void Fifo_Run()
|
|
{
|
|
SCPFifoStruct &_fifo = CommandProcessor::fifo;
|
|
s32 distToSend;
|
|
|
|
// check if we are able to run this buffer
|
|
while (_fifo.bFF_GPReadEnable && ((!_fifo.bFF_BPEnable && _fifo.CPReadWriteDistance) || (_fifo.bFF_BPEnable && !_fifo.bFF_Breakpoint)))
|
|
{
|
|
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);
|
|
|
|
// If we are in BP mode we only send 32B chunks to Video plugin for BP checking
|
|
if (_fifo.bFF_BPEnable)
|
|
{
|
|
// Sometimes we have already exceeded the BP even before it is set
|
|
// so careful check is required
|
|
if (
|
|
(readPtr == _fifo.CPBreakpoint) ||
|
|
//(readPtr <= _fifo.CPBreakpoint && readPtr + 32 > _fifo.CPBreakpoint) ||
|
|
(readPtr <= _fifo.CPWritePointer && _fifo.CPWritePointer < _fifo.CPBreakpoint) ||
|
|
(readPtr <= _fifo.CPWritePointer && readPtr > _fifo.CPBreakpoint) ||
|
|
(readPtr > _fifo.CPBreakpoint && _fifo.CPBreakpoint > _fifo.CPWritePointer)
|
|
)
|
|
{
|
|
Common::AtomicStore(_fifo.bFF_Breakpoint, 1);
|
|
CommandProcessor::UpdateInterruptsFromVideoPlugin(true);
|
|
CommandProcessor::FifoCriticalLeave();
|
|
break;
|
|
}
|
|
distToSend = 32;
|
|
|
|
if ( readPtr >= _fifo.CPEnd)
|
|
readPtr = _fifo.CPBase;
|
|
else
|
|
readPtr += 32;
|
|
}
|
|
// If we are not in BP mode we send all the chunk we have to speed up
|
|
else
|
|
{
|
|
distToSend = _fifo.CPReadWriteDistance;
|
|
// send 1024B chunk max length to have better control over PeekMessages' period
|
|
distToSend = distToSend > 1024 ? 1024 : distToSend;
|
|
// add 32 bytes because the cp end points to the start of the last 32 byte chunk
|
|
if ((distToSend + readPtr) >= (_fifo.CPEnd + 32)) // TODO: better?
|
|
{
|
|
distToSend =(_fifo.CPEnd + 32) - readPtr;
|
|
readPtr = _fifo.CPBase;
|
|
}
|
|
else
|
|
readPtr += distToSend;
|
|
}
|
|
|
|
// Execute new instructions found in uData
|
|
Fifo_SendFifoData(uData, distToSend);
|
|
|
|
Common::AtomicStore(_fifo.CPReadPointer, readPtr);
|
|
Common::AtomicAdd(_fifo.CPReadWriteDistance, -distToSend);
|
|
|
|
CommandProcessor::FifoCriticalLeave();
|
|
}
|
|
|
|
CommandProcessor::SetFifoIdleFromVideoPlugin();
|
|
}
|
|
|
|
// Regular thread
|
|
THREAD_RETURN fifo_thread(void* lpParameter)
|
|
{
|
|
while (fifoStateRun)
|
|
{
|
|
Fifo_Run();
|
|
|
|
// Must use YieldCPU() in this loop. SLEEP(1) will make MP2
|
|
// hang on boot.
|
|
if (EmuRunning)
|
|
Common::YieldCPU();
|
|
else
|
|
fifo_run_event.MsgWait();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Description: Main FIFO update loop
|
|
// Purpose: Keep the Core HW updated about the CPU-GPU distance
|
|
void Fifo_EnterLoop(const SVideoInitialize &video_init)
|
|
{
|
|
fifoStateRun = true;
|
|
video_initialize = video_init;
|
|
|
|
if (g_ActiveConfig.bUseFIFOThread) // threaded mode
|
|
{
|
|
g_hFifoThread = new Common::Thread(fifo_thread, NULL);
|
|
while (fifoStateRun)
|
|
{
|
|
video_initialize.pPeekMessages();
|
|
|
|
// The two VideoFifo checks below 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_CheckEFBAccess();
|
|
VideoFifo_CheckSwapRequest();
|
|
|
|
SLEEP(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (fifoStateRun)
|
|
{
|
|
video_initialize.pPeekMessages();
|
|
VideoFifo_CheckEFBAccess();
|
|
VideoFifo_CheckSwapRequest();
|
|
|
|
Fifo_Run();
|
|
|
|
if (EmuRunning)
|
|
Common::YieldCPU();
|
|
else
|
|
fifo_run_event.MsgWait();
|
|
}
|
|
}
|
|
} |