diff options
| author | Ryan Houdek <Sonicadvance1@gmail.com> | 2013-12-31 19:18:30 -0600 |
|---|---|---|
| committer | Ryan Houdek <Sonicadvance1@gmail.com> | 2013-12-31 19:18:30 -0600 |
| commit | 1118226f270d2b44d10dd3cebd9f89fd38042680 (patch) | |
| tree | 9dd80995633c70581443d40f58d6ac35837e0bd4 /Source/Core/VideoCommon/Fifo.cpp | |
| parent | 8d8b0fc884367bc4d433d698a790ef5badee6957 (diff) | |
| parent | 16824d5fd17b43b156706bf02a8063b389604766 (diff) | |
Merge branch 'master' into buffer_storage
Diffstat (limited to 'Source/Core/VideoCommon/Fifo.cpp')
| -rw-r--r-- | Source/Core/VideoCommon/Fifo.cpp | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/Source/Core/VideoCommon/Fifo.cpp b/Source/Core/VideoCommon/Fifo.cpp new file mode 100644 index 0000000000..92b9753623 --- /dev/null +++ b/Source/Core/VideoCommon/Fifo.cpp @@ -0,0 +1,247 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "VideoConfig.h" +#include "MemoryUtil.h" +#include "Thread.h" +#include "Atomic.h" +#include "OpcodeDecoding.h" +#include "CommandProcessor.h" +#include "PixelEngine.h" +#include "ChunkFile.h" +#include "Fifo.h" +#include "HW/Memmap.h" +#include "Core.h" +#include "CoreTiming.h" + +volatile bool g_bSkipCurrentFrame = false; +extern u8* g_pVideoData; + +namespace +{ +static volatile bool GpuRunningState = false; +static volatile bool EmuRunningState = false; +static std::mutex m_csHWVidOccupied; +// STATE_TO_SAVE +static u8 *videoBuffer; +static int size = 0; +} // namespace + +void Fifo_DoState(PointerWrap &p) +{ + p.DoArray(videoBuffer, FIFO_SIZE); + p.Do(size); + p.DoPointer(g_pVideoData, videoBuffer); + p.Do(g_bSkipCurrentFrame); +} + +void Fifo_PauseAndLock(bool doLock, bool unpauseOnUnlock) +{ + if (doLock) + { + EmulatorState(false); + if (!Core::IsGPUThread()) + m_csHWVidOccupied.lock(); + _dbg_assert_(COMMON, !CommandProcessor::fifo.isGpuReadingData); + } + else + { + if (unpauseOnUnlock) + EmulatorState(true); + if (!Core::IsGPUThread()) + m_csHWVidOccupied.unlock(); + } +} + + +void Fifo_Init() +{ + videoBuffer = (u8*)AllocateMemoryPages(FIFO_SIZE); + size = 0; + GpuRunningState = false; + Common::AtomicStore(CommandProcessor::VITicks, CommandProcessor::m_cpClockOrigin); +} + +void Fifo_Shutdown() +{ + if (GpuRunningState) PanicAlert("Fifo shutting down while active"); + FreeMemoryPages(videoBuffer, FIFO_SIZE); +} + +u8* GetVideoBufferStartPtr() +{ + return videoBuffer; +} + +u8* GetVideoBufferEndPtr() +{ + return &videoBuffer[size]; +} + +void Fifo_SetRendering(bool enabled) +{ + g_bSkipCurrentFrame = !enabled; +} + +// May be executed from any thread, even the graphics thread. +// Created to allow for self shutdown. +void ExitGpuLoop() +{ + // This should break the wait loop in CPU thread + CommandProcessor::fifo.bFF_GPReadEnable = false; + SCPFifoStruct &fifo = CommandProcessor::fifo; + while(fifo.isGpuReadingData) Common::YieldCPU(); + // Terminate GPU thread loop + GpuRunningState = false; + EmuRunningState = true; +} + +void EmulatorState(bool running) +{ + EmuRunningState = running; +} + + +// Description: RunGpuLoop() sends data through this function. +void ReadDataFromFifo(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 (size = %i, len = %i at %08x)", size, len, 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; +} + +void ResetVideoBuffer() +{ + g_pVideoData = videoBuffer; + size = 0; +} + + +// Description: Main FIFO update loop +// Purpose: Keep the Core HW updated about the CPU-GPU distance +void RunGpuLoop() +{ + std::lock_guard<std::mutex> lk(m_csHWVidOccupied); + GpuRunningState = true; + SCPFifoStruct &fifo = CommandProcessor::fifo; + u32 cyclesExecuted = 0; + + while (GpuRunningState) + { + g_video_backend->PeekMessages(); + + VideoFifo_CheckAsyncRequest(); + + CommandProcessor::SetCpStatus(); + + Common::AtomicStore(CommandProcessor::VITicks, CommandProcessor::m_cpClockOrigin); + + // check if we are able to run this buffer + while (GpuRunningState && !CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint()) + { + fifo.isGpuReadingData = true; + CommandProcessor::isPossibleWaitingSetDrawDone = fifo.bFF_GPLinkEnable ? true : false; + + if (!Core::g_CoreStartupParameter.bSyncGPU || Common::AtomicLoad(CommandProcessor::VITicks) > CommandProcessor::m_cpClockOrigin) + { + u32 readPtr = fifo.CPReadPointer; + u8 *uData = Memory::GetPointer(readPtr); + + if (readPtr == fifo.CPEnd) + readPtr = fifo.CPBase; + else + readPtr += 32; + + _assert_msg_(COMMANDPROCESSOR, (s32)fifo.CPReadWriteDistance - 32 >= 0 , + "Negative fifo.CPReadWriteDistance = %i in FIFO Loop !\nThat can produce instability in the game. Please report it.", fifo.CPReadWriteDistance - 32); + + ReadDataFromFifo(uData, 32); + + cyclesExecuted = OpcodeDecoder_Run(g_bSkipCurrentFrame); + + if (Core::g_CoreStartupParameter.bSyncGPU && Common::AtomicLoad(CommandProcessor::VITicks) > cyclesExecuted) + Common::AtomicAdd(CommandProcessor::VITicks, -(s32)cyclesExecuted); + + Common::AtomicStore(fifo.CPReadPointer, readPtr); + Common::AtomicAdd(fifo.CPReadWriteDistance, -32); + if((GetVideoBufferEndPtr() - g_pVideoData) == 0) + Common::AtomicStore(fifo.SafeCPReadPointer, fifo.CPReadPointer); + } + + CommandProcessor::SetCpStatus(); + + // This call is pretty important in DualCore mode and must be called in the FIFO Loop. + // If we don't, s_swapRequested 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::isPossibleWaitingSetDrawDone = false; + } + + fifo.isGpuReadingData = false; + + if (EmuRunningState) + { + // NOTE(jsd): Calling SwitchToThread() on Windows 7 x64 is a hot spot, according to profiler. + // See https://docs.google.com/spreadsheet/ccc?key=0Ah4nh0yGtjrgdFpDeF9pS3V6RUotRVE3S3J4TGM1NlE#gid=0 + // for benchmark details. +#if 0 + Common::YieldCPU(); +#endif + } + else + { + // While the emu is paused, we still handle async requests then sleep. + while (!EmuRunningState) + { + g_video_backend->PeekMessages(); + m_csHWVidOccupied.unlock(); + Common::SleepCurrentThread(1); + m_csHWVidOccupied.lock(); + } + } + } +} + + +bool AtBreakpoint() +{ + SCPFifoStruct &fifo = CommandProcessor::fifo; + return fifo.bFF_BPEnable && (fifo.CPReadPointer == fifo.CPBreakpoint); +} + +void RunGpu() +{ + SCPFifoStruct &fifo = CommandProcessor::fifo; + while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint() ) + { + u8 *uData = Memory::GetPointer(fifo.CPReadPointer); + + FPURoundMode::SaveSIMDState(); + FPURoundMode::LoadDefaultSIMDState(); + ReadDataFromFifo(uData, 32); + OpcodeDecoder_Run(g_bSkipCurrentFrame); + FPURoundMode::LoadSIMDState(); + + //DEBUG_LOG(COMMANDPROCESSOR, "Fifo wraps to base"); + + if (fifo.CPReadPointer == fifo.CPEnd) + fifo.CPReadPointer = fifo.CPBase; + else + fifo.CPReadPointer += 32; + + fifo.CPReadWriteDistance -= 32; + } + CommandProcessor::SetCpStatus(); +} |
