mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 14:49:42 -06:00
Merge branch 'FIFO-BP'
# By skidau (30) and Pierre Bourdon (1) * FIFO-BP: (31 commits) Set g_bSignalTokenInterrupt on the main thread. Fixes the random hang in Harry Potter: Prisoner of Azkaban. Used a scheduled event to generate the ARAM DMA interrupt if the DMA is greater than a certain size. Fixes NFS:HP2 GC. Bumped up the disc transfer speed enough to prevent audio stuttering in Gauntlet: Dark Legacy. Enabled Synchronise GPU on "SPEED CHALLENGE - Jacques Villeneuve's Racing Vision". Required to go in-game. Added direct GameCube controller commands to the Serial Interface emulation. Fixes the controls in MaxPlay Classic Games Volume 1 and the Action Replay disc. Increased the FIFO buffer size to 2MB from 1MB. Fixes Killer 7's Angel boss. Used an immediate GenerateDSPInterrupt when transferring data from ARAM to MRAM and a scheduled DSP interrupt when transferring data from MRAM to ARAM. Fixes the audio cutting in and out in the Resident Evil GC games using DSP HLE. Triggered the ARAM interrupt by the scheduler instead of directly in function. Implemented proper timing for the sample counter in the AudioInterface, removing the previous hack. Cleaned up some of the audio streaming code. Skipped the EE check if there is a CP interrupt pending. Disabled "Speed up disc transfer" from the ZTP GC game ini. Removed the disc seek times for GC games and removed the disc speed option on Wii games. Checked for external exceptions only in mtmsr. Delayed the interrupts in the EXI Channel. Merge aram-dma-fixes (r76a13604ef49b522281af75675f044d59a74e871) Added a patch that bypasses the FIFO reset code in Wallace and Gromit: Project Zoo, allowing it to go in-game. Made vertex loading take constant time. Increased the cycle time of the vertex command. Fixes "Speed Challenge: Jacques Villeneuve's Racing Vision". Moved the setting of the Finish interrupt signal back to the main thread as it was causing Wii games like Resident Evil 4 (Wii) to hang. Profile stores, fp stores and ps stores only to the fifo write addresses list. This should make the JIT a little faster as it will not be checking for external exceptions unnecessarily. ... Conflicts: Source/Core/VideoCommon/Src/PixelEngine.cpp
This commit is contained in:
@ -32,6 +32,8 @@
|
||||
#include "HW/GPFifo.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include "DLCache.h"
|
||||
#include "HW/SystemTimers.h"
|
||||
#include "Core.h"
|
||||
|
||||
namespace CommandProcessor
|
||||
{
|
||||
@ -57,12 +59,15 @@ static bool bProcessFifoAllDistance = false;
|
||||
|
||||
volatile bool isPossibleWaitingSetDrawDone = false;
|
||||
volatile bool isHiWatermarkActive = false;
|
||||
volatile bool isLoWatermarkActive = false;
|
||||
volatile bool interruptSet= false;
|
||||
volatile bool interruptWaiting= false;
|
||||
volatile bool interruptTokenWaiting = false;
|
||||
volatile bool interruptFinishWaiting = false;
|
||||
volatile bool waitingForPEInterruptDisable = false;
|
||||
|
||||
volatile u32 VITicks = CommandProcessor::m_cpClockOrigin;
|
||||
|
||||
bool IsOnThread()
|
||||
{
|
||||
return SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread;
|
||||
@ -88,6 +93,7 @@ void DoState(PointerWrap &p)
|
||||
p.Do(bProcessFifoToLoWatermark);
|
||||
p.Do(bProcessFifoAllDistance);
|
||||
p.Do(isHiWatermarkActive);
|
||||
p.Do(isLoWatermarkActive);
|
||||
p.Do(isPossibleWaitingSetDrawDone);
|
||||
p.Do(interruptSet);
|
||||
p.Do(interruptWaiting);
|
||||
@ -119,7 +125,7 @@ void Init()
|
||||
m_tokenReg = 0;
|
||||
|
||||
memset(&fifo,0,sizeof(fifo));
|
||||
fifo.CPCmdIdle = 1 ;
|
||||
fifo.CPCmdIdle = 1;
|
||||
fifo.CPReadIdle = 1;
|
||||
fifo.bFF_Breakpoint = 0;
|
||||
fifo.bFF_HiWatermark = 0;
|
||||
@ -136,6 +142,7 @@ void Init()
|
||||
bProcessFifoAllDistance = false;
|
||||
isPossibleWaitingSetDrawDone = false;
|
||||
isHiWatermarkActive = false;
|
||||
isLoWatermarkActive = false;
|
||||
|
||||
et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper);
|
||||
}
|
||||
@ -294,7 +301,6 @@ void Read16(u16& _rReturnValue, const u32 _Address)
|
||||
|
||||
void Write16(const u16 _Value, const u32 _Address)
|
||||
{
|
||||
|
||||
INFO_LOG(COMMANDPROCESSOR, "(write16): 0x%04x @ 0x%08x",_Value,_Address);
|
||||
|
||||
switch (_Address & 0xFFF)
|
||||
@ -405,7 +411,8 @@ void Write16(const u16 _Value, const u32 _Address)
|
||||
{
|
||||
GPFifo::ResetGatherPipe();
|
||||
ResetVideoBuffer();
|
||||
}else
|
||||
}
|
||||
else
|
||||
{
|
||||
ResetVideoBuffer();
|
||||
}
|
||||
@ -461,7 +468,7 @@ void STACKALIGN GatherPipeBursted()
|
||||
}
|
||||
|
||||
if (IsOnThread())
|
||||
SetOverflowStatusFromGatherPipe();
|
||||
SetCpStatus();
|
||||
|
||||
// update the fifo-pointer
|
||||
if (fifo.CPWritePointer >= fifo.CPEnd)
|
||||
@ -511,19 +518,6 @@ void AbortFrame()
|
||||
|
||||
}
|
||||
|
||||
void SetOverflowStatusFromGatherPipe()
|
||||
{
|
||||
fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark);
|
||||
isHiWatermarkActive = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt && m_CPCtrlReg.GPReadEnable;
|
||||
|
||||
if (isHiWatermarkActive)
|
||||
{
|
||||
interruptSet = true;
|
||||
INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
|
||||
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true);
|
||||
}
|
||||
}
|
||||
|
||||
void SetCpStatus()
|
||||
{
|
||||
// overflow & underflow check
|
||||
@ -531,30 +525,33 @@ void SetCpStatus()
|
||||
fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark);
|
||||
|
||||
// breakpoint
|
||||
if (fifo.bFF_BPEnable)
|
||||
{
|
||||
if (fifo.CPBreakpoint == fifo.CPReadPointer)
|
||||
{
|
||||
if (!fifo.bFF_Breakpoint)
|
||||
if (Core::IsGPUThread())
|
||||
{
|
||||
if (fifo.bFF_BPEnable)
|
||||
{
|
||||
if (fifo.CPBreakpoint == fifo.CPReadPointer)
|
||||
{
|
||||
INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %i", fifo.CPReadPointer);
|
||||
fifo.bFF_Breakpoint = true;
|
||||
IncrementCheckContextId();
|
||||
if (!fifo.bFF_Breakpoint)
|
||||
{
|
||||
INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %i", fifo.CPReadPointer);
|
||||
fifo.bFF_Breakpoint = true;
|
||||
IncrementCheckContextId();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fifo.bFF_Breakpoint)
|
||||
INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i", fifo.CPReadPointer);
|
||||
fifo.bFF_Breakpoint = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fifo.bFF_Breakpoint)
|
||||
INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i", fifo.CPReadPointer);
|
||||
fifo.bFF_Breakpoint = false;
|
||||
fifo.bFF_Breakpoint = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fifo.bFF_Breakpoint)
|
||||
INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i", fifo.CPReadPointer);
|
||||
fifo.bFF_Breakpoint = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool bpInt = fifo.bFF_Breakpoint && fifo.bFF_BPInt;
|
||||
bool ovfInt = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt;
|
||||
@ -562,17 +559,27 @@ void SetCpStatus()
|
||||
|
||||
bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable;
|
||||
|
||||
isHiWatermarkActive = ovfInt && m_CPCtrlReg.GPReadEnable;
|
||||
isHiWatermarkActive = ovfInt && m_CPCtrlReg.GPReadEnable;
|
||||
isLoWatermarkActive = undfInt && m_CPCtrlReg.GPReadEnable;
|
||||
|
||||
if (interrupt != interruptSet && !interruptWaiting)
|
||||
{
|
||||
u64 userdata = interrupt?1:0;
|
||||
if (IsOnThread())
|
||||
{
|
||||
if(!interrupt || bpInt || undfInt)
|
||||
if(!interrupt || bpInt || undfInt || ovfInt)
|
||||
{
|
||||
interruptWaiting = true;
|
||||
CommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
|
||||
if (Core::IsGPUThread())
|
||||
{
|
||||
interruptWaiting = true;
|
||||
CommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
|
||||
}
|
||||
else if (Core::IsCPUThread())
|
||||
{
|
||||
interruptSet = interrupt;
|
||||
INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
|
||||
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, interrupt);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -596,7 +603,7 @@ void ProcessFifoAllDistance()
|
||||
if (IsOnThread())
|
||||
{
|
||||
while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable &&
|
||||
fifo.CPReadWriteDistance && !AtBreakpoint() && !PixelEngine::WaitingForPEInterrupt())
|
||||
fifo.CPReadWriteDistance && !AtBreakpoint())
|
||||
Common::YieldCPU();
|
||||
}
|
||||
bProcessFifoAllDistance = false;
|
||||
@ -617,15 +624,11 @@ void SetCpStatusRegister()
|
||||
{
|
||||
// Here always there is one fifo attached to the GPU
|
||||
m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint;
|
||||
m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint) ;
|
||||
m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance;
|
||||
m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || AtBreakpoint() || (fifo.CPReadPointer == fifo.CPWritePointer);
|
||||
m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance || AtBreakpoint() || !fifo.bFF_GPReadEnable;
|
||||
m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark;
|
||||
m_CPStatusReg.OverflowHiWatermark = fifo.bFF_HiWatermark;
|
||||
|
||||
// HACK to compensate for slow response to PE interrupts in Time Splitters: Future Perfect
|
||||
if (IsOnThread())
|
||||
PixelEngine::ResumeWaitingForPEInterrupt();
|
||||
|
||||
INFO_LOG(COMMANDPROCESSOR,"\t Read from STATUS_REGISTER : %04x", m_CPStatusReg.Hex);
|
||||
DEBUG_LOG(COMMANDPROCESSOR, "(r) status: iBP %s | fReadIdle %s | fCmdIdle %s | iOvF %s | iUndF %s"
|
||||
, m_CPStatusReg.Breakpoint ? "ON" : "OFF"
|
||||
@ -693,4 +696,12 @@ void SetCpClearRegister()
|
||||
// }
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
while (VITicks > m_cpClockOrigin && fifo.isGpuReadingData && IsOnThread())
|
||||
Common::YieldCPU();
|
||||
|
||||
if (fifo.isGpuReadingData)
|
||||
Common::AtomicAdd(VITicks, SystemTimers::GetTicksPerSecond() / 10000);
|
||||
}
|
||||
} // end of namespace CommandProcessor
|
||||
|
@ -31,6 +31,7 @@ namespace CommandProcessor
|
||||
extern SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread.
|
||||
extern volatile bool isPossibleWaitingSetDrawDone; //This one is used for sync gfx thread and emulator thread.
|
||||
extern volatile bool isHiWatermarkActive;
|
||||
extern volatile bool isLoWatermarkActive;
|
||||
extern volatile bool interruptSet;
|
||||
extern volatile bool interruptWaiting;
|
||||
extern volatile bool interruptTokenWaiting;
|
||||
@ -140,6 +141,9 @@ union UCPClearReg
|
||||
UCPClearReg(u16 _hex) {Hex = _hex; }
|
||||
};
|
||||
|
||||
// Can be any number, low enough to not be below the number of clocks executed by the GPU per CP_PERIOD
|
||||
const static u32 m_cpClockOrigin = 200000;
|
||||
|
||||
// Init
|
||||
void Init();
|
||||
void Shutdown();
|
||||
@ -161,11 +165,14 @@ bool AllowIdleSkipping();
|
||||
void SetCpClearRegister();
|
||||
void SetCpControlRegister();
|
||||
void SetCpStatusRegister();
|
||||
void SetOverflowStatusFromGatherPipe();
|
||||
void ProcessFifoToLoWatermark();
|
||||
void ProcessFifoAllDistance();
|
||||
void ProcessFifoEvents();
|
||||
void AbortFrame();
|
||||
|
||||
void Update();
|
||||
extern volatile u32 VITicks;
|
||||
|
||||
} // namespace CommandProcessor
|
||||
|
||||
#endif // _COMMANDPROCESSOR_H
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "Fifo.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include "Core.h"
|
||||
#include "CoreTiming.h"
|
||||
|
||||
volatile bool g_bSkipCurrentFrame = false;
|
||||
extern u8* g_pVideoData;
|
||||
@ -72,6 +73,7 @@ void Fifo_Init()
|
||||
videoBuffer = (u8*)AllocateMemoryPages(FIFO_SIZE);
|
||||
size = 0;
|
||||
GpuRunningState = false;
|
||||
Common::AtomicStore(CommandProcessor::VITicks, CommandProcessor::m_cpClockOrigin);
|
||||
}
|
||||
|
||||
void Fifo_Shutdown()
|
||||
@ -123,7 +125,7 @@ void ReadDataFromFifo(u8* _uData, u32 len)
|
||||
size -= pos;
|
||||
if (size + len > FIFO_SIZE)
|
||||
{
|
||||
PanicAlert("FIFO out of bounds (sz = %i, at %08x)", size, pos);
|
||||
PanicAlert("FIFO out of bounds (sz = %i, len = %i at %08x)", size, len, pos);
|
||||
}
|
||||
memmove(&videoBuffer[0], &videoBuffer[pos], size);
|
||||
g_pVideoData = videoBuffer;
|
||||
@ -147,6 +149,7 @@ void RunGpuLoop()
|
||||
std::lock_guard<std::mutex> lk(m_csHWVidOccupied);
|
||||
GpuRunningState = true;
|
||||
SCPFifoStruct &fifo = CommandProcessor::fifo;
|
||||
u32 cyclesExecuted = 0;
|
||||
|
||||
while (GpuRunningState)
|
||||
{
|
||||
@ -155,31 +158,41 @@ void RunGpuLoop()
|
||||
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() && !PixelEngine::WaitingForPEInterrupt())
|
||||
while (GpuRunningState && !CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint())
|
||||
{
|
||||
if (!GpuRunningState) break;
|
||||
|
||||
fifo.isGpuReadingData = true;
|
||||
CommandProcessor::isPossibleWaitingSetDrawDone = fifo.bFF_GPLinkEnable ? true : false;
|
||||
|
||||
u32 readPtr = fifo.CPReadPointer;
|
||||
u8 *uData = Memory::GetPointer(readPtr);
|
||||
|
||||
if (readPtr == fifo.CPEnd) readPtr = fifo.CPBase;
|
||||
if (Common::AtomicLoad(CommandProcessor::VITicks) > CommandProcessor::m_cpClockOrigin || !Core::g_CoreStartupParameter.bSyncGPU)
|
||||
{
|
||||
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 inestabilty in the game. Please report it.", fifo.CPReadWriteDistance - 32);
|
||||
|
||||
ReadDataFromFifo(uData, 32);
|
||||
|
||||
OpcodeDecoder_Run(g_bSkipCurrentFrame);
|
||||
|
||||
Common::AtomicStore(fifo.CPReadPointer, readPtr);
|
||||
Common::AtomicAdd(fifo.CPReadWriteDistance, -32);
|
||||
if((GetVideoBufferEndPtr() - g_pVideoData) == 0)
|
||||
Common::AtomicStore(fifo.SafeCPReadPointer, fifo.CPReadPointer);
|
||||
_assert_msg_(COMMANDPROCESSOR, (s32)fifo.CPReadWriteDistance - 32 >= 0 ,
|
||||
"Negative fifo.CPReadWriteDistance = %i in FIFO Loop !\nThat can produce instabilty in the game. Please report it.", fifo.CPReadWriteDistance - 32);
|
||||
|
||||
ReadDataFromFifo(uData, 32);
|
||||
|
||||
cyclesExecuted = OpcodeDecoder_Run(g_bSkipCurrentFrame);
|
||||
|
||||
if (Common::AtomicLoad(CommandProcessor::VITicks) > cyclesExecuted && Core::g_CoreStartupParameter.bSyncGPU)
|
||||
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.
|
||||
@ -188,7 +201,7 @@ void RunGpuLoop()
|
||||
VideoFifo_CheckAsyncRequest();
|
||||
CommandProcessor::isPossibleWaitingSetDrawDone = false;
|
||||
}
|
||||
|
||||
|
||||
fifo.isGpuReadingData = false;
|
||||
|
||||
|
||||
@ -217,23 +230,23 @@ bool AtBreakpoint()
|
||||
|
||||
void RunGpu()
|
||||
{
|
||||
SCPFifoStruct &fifo = CommandProcessor::fifo;
|
||||
while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint() )
|
||||
{
|
||||
u8 *uData = Memory::GetPointer(fifo.CPReadPointer);
|
||||
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);
|
||||
u32 count = OpcodeDecoder_Run(g_bSkipCurrentFrame);
|
||||
FPURoundMode::LoadSIMDState();
|
||||
|
||||
//DEBUG_LOG(COMMANDPROCESSOR, "Fifo wraps to base");
|
||||
//DEBUG_LOG(COMMANDPROCESSOR, "Fifo wraps to base");
|
||||
|
||||
if (fifo.CPReadPointer == fifo.CPEnd) fifo.CPReadPointer = fifo.CPBase;
|
||||
else fifo.CPReadPointer += 32;
|
||||
if (fifo.CPReadPointer == fifo.CPEnd) fifo.CPReadPointer = fifo.CPBase;
|
||||
else fifo.CPReadPointer += 32;
|
||||
|
||||
fifo.CPReadWriteDistance -= 32;
|
||||
}
|
||||
CommandProcessor::SetCpStatus();
|
||||
fifo.CPReadWriteDistance -= 32;
|
||||
}
|
||||
CommandProcessor::SetCpStatus();
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
#define FIFO_SIZE (1024*1024)
|
||||
#define FIFO_SIZE (2*1024*1024)
|
||||
|
||||
extern volatile bool g_bSkipCurrentFrame;
|
||||
|
||||
|
@ -136,29 +136,38 @@ void ExecuteDisplayList(u32 address, u32 size)
|
||||
InterpretDisplayList(address, size);
|
||||
}
|
||||
|
||||
bool FifoCommandRunnable()
|
||||
u32 FifoCommandRunnable(u32 &command_size)
|
||||
{
|
||||
u32 cycleTime = 0;
|
||||
u32 buffer_size = (u32)(GetVideoBufferEndPtr() - g_pVideoData);
|
||||
if (buffer_size == 0)
|
||||
return false; // can't peek
|
||||
return 0; // can't peek
|
||||
|
||||
u8 cmd_byte = DataPeek8(0);
|
||||
u32 command_size = 0;
|
||||
|
||||
switch (cmd_byte)
|
||||
{
|
||||
case GX_NOP: // Hm, this means that we scan over nop streams pretty slowly...
|
||||
command_size = 1;
|
||||
cycleTime = 6;
|
||||
break;
|
||||
case GX_CMD_INVL_VC: // Invalidate Vertex Cache - no parameters
|
||||
command_size = 1;
|
||||
cycleTime = 6;
|
||||
break;
|
||||
case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that
|
||||
command_size = 1;
|
||||
cycleTime = 6;
|
||||
break;
|
||||
|
||||
case GX_LOAD_BP_REG:
|
||||
command_size = 5;
|
||||
cycleTime = 12;
|
||||
break;
|
||||
|
||||
case GX_LOAD_CP_REG:
|
||||
command_size = 6;
|
||||
cycleTime = 12;
|
||||
break;
|
||||
|
||||
case GX_LOAD_INDX_A:
|
||||
@ -166,10 +175,39 @@ bool FifoCommandRunnable()
|
||||
case GX_LOAD_INDX_C:
|
||||
case GX_LOAD_INDX_D:
|
||||
command_size = 5;
|
||||
cycleTime = 6; // TODO
|
||||
break;
|
||||
|
||||
case GX_CMD_CALL_DL:
|
||||
command_size = 9;
|
||||
case GX_CMD_CALL_DL:
|
||||
{
|
||||
// FIXME: Calculate the cycle time of the display list.
|
||||
//u32 address = DataPeek32(1);
|
||||
//u32 size = DataPeek32(5);
|
||||
//u8* old_pVideoData = g_pVideoData;
|
||||
//u8* startAddress = Memory::GetPointer(address);
|
||||
|
||||
//// Avoid the crash if Memory::GetPointer failed ..
|
||||
//if (startAddress != 0)
|
||||
//{
|
||||
// g_pVideoData = startAddress;
|
||||
// u8 *end = g_pVideoData + size;
|
||||
// u32 step = 0;
|
||||
// while (g_pVideoData < end)
|
||||
// {
|
||||
// cycleTime += FifoCommandRunnable(step);
|
||||
// g_pVideoData += step;
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// cycleTime = 45;
|
||||
//}
|
||||
|
||||
//// reset to the old pointer
|
||||
//g_pVideoData = old_pVideoData;
|
||||
command_size = 9;
|
||||
cycleTime = 45; // This is unverified
|
||||
}
|
||||
break;
|
||||
|
||||
case GX_LOAD_XF_REG:
|
||||
@ -180,11 +218,12 @@ bool FifoCommandRunnable()
|
||||
command_size = 1 + 4;
|
||||
u32 Cmd2 = DataPeek32(1);
|
||||
int transfer_size = ((Cmd2 >> 16) & 15) + 1;
|
||||
command_size += transfer_size * 4;
|
||||
command_size += transfer_size * 4;
|
||||
cycleTime = 18 + 6 * transfer_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -198,10 +237,11 @@ bool FifoCommandRunnable()
|
||||
command_size = 1 + 2;
|
||||
u16 numVertices = DataPeek16(1);
|
||||
command_size += numVertices * VertexLoaderManager::GetVertexSize(cmd_byte & GX_VAT_MASK);
|
||||
cycleTime = 1600; // This depends on the number of pixels rendered
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -248,11 +288,19 @@ bool FifoCommandRunnable()
|
||||
}
|
||||
|
||||
if (command_size > buffer_size)
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
// INFO_LOG("OP detected: cmd_byte 0x%x size %i buffer %i",cmd_byte, command_size, buffer_size);
|
||||
if (cycleTime == 0)
|
||||
cycleTime = 6;
|
||||
|
||||
return true;
|
||||
return cycleTime;
|
||||
}
|
||||
|
||||
u32 FifoCommandRunnable()
|
||||
{
|
||||
u32 command_size = 0;
|
||||
return FifoCommandRunnable(command_size);
|
||||
}
|
||||
|
||||
static void Decode()
|
||||
@ -461,16 +509,15 @@ void OpcodeDecoder_Shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
void OpcodeDecoder_Run(bool skipped_frame)
|
||||
u32 OpcodeDecoder_Run(bool skipped_frame)
|
||||
{
|
||||
if (!skipped_frame)
|
||||
u32 totalCycles = 0;
|
||||
u32 cycles = FifoCommandRunnable();
|
||||
while (cycles > 0)
|
||||
{
|
||||
while (FifoCommandRunnable())
|
||||
Decode();
|
||||
}
|
||||
else
|
||||
{
|
||||
while (FifoCommandRunnable())
|
||||
DecodeSemiNop();
|
||||
skipped_frame ? DecodeSemiNop() : Decode();
|
||||
totalCycles += cycles;
|
||||
cycles = FifoCommandRunnable();
|
||||
}
|
||||
return totalCycles;
|
||||
}
|
||||
|
@ -50,6 +50,6 @@ extern bool g_bRecordFifoData;
|
||||
|
||||
void OpcodeDecoder_Init();
|
||||
void OpcodeDecoder_Shutdown();
|
||||
void OpcodeDecoder_Run(bool skipped_frame);
|
||||
u32 OpcodeDecoder_Run(bool skipped_frame);
|
||||
void ExecuteDisplayList(u32 address, u32 size);
|
||||
#endif // _OPCODE_DECODING_H
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include "HW/ProcessorInterface.h"
|
||||
#include "DLCache.h"
|
||||
#include "State.h"
|
||||
#include "PerfQueryBase.h"
|
||||
|
||||
namespace PixelEngine
|
||||
{
|
||||
@ -113,14 +112,14 @@ static UPEAlphaReadReg m_AlphaRead;
|
||||
static UPECtrlReg m_Control;
|
||||
//static u16 m_Token; // token value most recently encountered
|
||||
|
||||
static bool g_bSignalTokenInterrupt;
|
||||
static bool g_bSignalFinishInterrupt;
|
||||
volatile u32 g_bSignalTokenInterrupt;
|
||||
volatile u32 g_bSignalFinishInterrupt;
|
||||
|
||||
static int et_SetTokenOnMainThread;
|
||||
static int et_SetFinishOnMainThread;
|
||||
|
||||
volatile bool interruptSetToken = false;
|
||||
volatile bool interruptSetFinish = false;
|
||||
volatile u32 interruptSetToken = 0;
|
||||
volatile u32 interruptSetFinish = 0;
|
||||
|
||||
u16 bbox[4];
|
||||
bool bbox_active;
|
||||
@ -164,10 +163,10 @@ void Init()
|
||||
m_AlphaModeConf.Hex = 0;
|
||||
m_AlphaRead.Hex = 0;
|
||||
|
||||
g_bSignalTokenInterrupt = false;
|
||||
g_bSignalFinishInterrupt = false;
|
||||
interruptSetToken = false;
|
||||
interruptSetFinish = false;
|
||||
g_bSignalTokenInterrupt = 0;
|
||||
g_bSignalFinishInterrupt = 0;
|
||||
interruptSetToken = 0;
|
||||
interruptSetFinish = 0;
|
||||
|
||||
et_SetTokenOnMainThread = CoreTiming::RegisterEvent("SetToken", SetToken_OnMainThread);
|
||||
et_SetFinishOnMainThread = CoreTiming::RegisterEvent("SetFinish", SetFinish_OnMainThread);
|
||||
@ -214,7 +213,7 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
|
||||
break;
|
||||
|
||||
case PE_TOKEN_REG:
|
||||
_uReturnValue = CommandProcessor::fifo.PEToken;
|
||||
_uReturnValue = Common::AtomicLoad(*(volatile u32*)&CommandProcessor::fifo.PEToken);
|
||||
INFO_LOG(PIXELENGINE, "(r16) TOKEN_REG : %04x", _uReturnValue);
|
||||
break;
|
||||
|
||||
@ -351,8 +350,8 @@ void Write16(const u16 _iValue, const u32 _iAddress)
|
||||
{
|
||||
UPECtrlReg tmpCtrl(_iValue);
|
||||
|
||||
if (tmpCtrl.PEToken) g_bSignalTokenInterrupt = false;
|
||||
if (tmpCtrl.PEFinish) g_bSignalFinishInterrupt = false;
|
||||
if (tmpCtrl.PEToken) g_bSignalTokenInterrupt = 0;
|
||||
if (tmpCtrl.PEFinish) g_bSignalFinishInterrupt = 0;
|
||||
|
||||
m_Control.PETokenEnable = tmpCtrl.PETokenEnable;
|
||||
m_Control.PEFinishEnable = tmpCtrl.PEFinishEnable;
|
||||
@ -398,14 +397,14 @@ void UpdateInterrupts()
|
||||
|
||||
void UpdateTokenInterrupt(bool active)
|
||||
{
|
||||
ProcessorInterface::SetInterrupt(INT_CAUSE_PE_TOKEN, active);
|
||||
interruptSetToken = active;
|
||||
ProcessorInterface::SetInterrupt(INT_CAUSE_PE_TOKEN, active);
|
||||
Common::AtomicStore(interruptSetToken, active ? 1 : 0);
|
||||
}
|
||||
|
||||
void UpdateFinishInterrupt(bool active)
|
||||
{
|
||||
ProcessorInterface::SetInterrupt(INT_CAUSE_PE_FINISH, active);
|
||||
interruptSetFinish = active;
|
||||
ProcessorInterface::SetInterrupt(INT_CAUSE_PE_FINISH, active);
|
||||
Common::AtomicStore(interruptSetFinish, active ? 1 : 0);
|
||||
}
|
||||
|
||||
// TODO(mb2): Refactor SetTokenINT_OnMainThread(u64 userdata, int cyclesLate).
|
||||
@ -415,20 +414,23 @@ void UpdateFinishInterrupt(bool active)
|
||||
// Called only if BPMEM_PE_TOKEN_INT_ID is ack by GP
|
||||
void SetToken_OnMainThread(u64 userdata, int cyclesLate)
|
||||
{
|
||||
//if (userdata >> 16)
|
||||
//{
|
||||
g_bSignalTokenInterrupt = true;
|
||||
//_dbg_assert_msg_(PIXELENGINE, (CommandProcessor::fifo.PEToken == (userdata&0xFFFF)), "WTF? BPMEM_PE_TOKEN_INT_ID's token != BPMEM_PE_TOKEN_ID's token" );
|
||||
INFO_LOG(PIXELENGINE, "VIDEO Backend raises INT_CAUSE_PE_TOKEN (btw, token: %04x)", CommandProcessor::fifo.PEToken);
|
||||
// XXX: No 16-bit atomic store available, so cheat and use 32-bit.
|
||||
// That's what we've always done. We're counting on fifo.PEToken to be
|
||||
// 4-byte padded.
|
||||
Common::AtomicStore(*(volatile u32*)&CommandProcessor::fifo.PEToken, userdata & 0xffff);
|
||||
INFO_LOG(PIXELENGINE, "VIDEO Backend raises INT_CAUSE_PE_TOKEN (btw, token: %04x)", CommandProcessor::fifo.PEToken);
|
||||
if (userdata >> 16)
|
||||
{
|
||||
Common::AtomicStore(*(volatile u32*)&g_bSignalTokenInterrupt, 1);
|
||||
UpdateInterrupts();
|
||||
CommandProcessor::interruptTokenWaiting = false;
|
||||
IncrementCheckContextId();
|
||||
//}
|
||||
}
|
||||
CommandProcessor::interruptTokenWaiting = false;
|
||||
IncrementCheckContextId();
|
||||
}
|
||||
|
||||
void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
|
||||
{
|
||||
g_bSignalFinishInterrupt = 1;
|
||||
Common::AtomicStore(*(volatile u32*)&g_bSignalFinishInterrupt, 1);
|
||||
UpdateInterrupts();
|
||||
CommandProcessor::interruptFinishWaiting = false;
|
||||
CommandProcessor::isPossibleWaitingSetDrawDone = false;
|
||||
@ -438,23 +440,13 @@ void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
|
||||
// THIS IS EXECUTED FROM VIDEO THREAD
|
||||
void SetToken(const u16 _token, const int _bSetTokenAcknowledge)
|
||||
{
|
||||
// TODO?: set-token-value and set-token-INT could be merged since set-token-INT own the token value.
|
||||
if (_bSetTokenAcknowledge) // set token INT
|
||||
{
|
||||
Common::AtomicStore(*(volatile u32*)&g_bSignalTokenInterrupt, 1);
|
||||
}
|
||||
|
||||
Common::AtomicStore(*(volatile u32*)&CommandProcessor::fifo.PEToken, _token);
|
||||
CommandProcessor::interruptTokenWaiting = true;
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16));
|
||||
}
|
||||
else // set token value
|
||||
{
|
||||
// we do it directly from videoThread because of
|
||||
// Super Monkey Ball
|
||||
// XXX: No 16-bit atomic store available, so cheat and use 32-bit.
|
||||
// That's what we've always done. We're counting on fifo.PEToken to be
|
||||
// 4-byte padded.
|
||||
Common::AtomicStore(*(volatile u32*)&CommandProcessor::fifo.PEToken, _token);
|
||||
}
|
||||
CommandProcessor::interruptTokenWaiting = true;
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16));
|
||||
IncrementCheckContextId();
|
||||
}
|
||||
|
||||
@ -477,7 +469,6 @@ void ResetSetFinish()
|
||||
{
|
||||
UpdateFinishInterrupt(false);
|
||||
g_bSignalFinishInterrupt = false;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -491,8 +482,7 @@ void ResetSetToken()
|
||||
if (g_bSignalTokenInterrupt)
|
||||
{
|
||||
UpdateTokenInterrupt(false);
|
||||
g_bSignalTokenInterrupt = false;
|
||||
|
||||
g_bSignalTokenInterrupt = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -500,17 +490,4 @@ void ResetSetToken()
|
||||
}
|
||||
CommandProcessor::interruptTokenWaiting = false;
|
||||
}
|
||||
|
||||
bool WaitingForPEInterrupt()
|
||||
{
|
||||
return !CommandProcessor::waitingForPEInterruptDisable && (CommandProcessor::interruptFinishWaiting || CommandProcessor::interruptTokenWaiting || interruptSetFinish || interruptSetToken);
|
||||
}
|
||||
|
||||
void ResumeWaitingForPEInterrupt()
|
||||
{
|
||||
interruptSetFinish = false;
|
||||
interruptSetToken = false;
|
||||
CommandProcessor::interruptFinishWaiting = false;
|
||||
CommandProcessor::interruptTokenWaiting = false;
|
||||
}
|
||||
} // end of namespace PixelEngine
|
||||
|
@ -81,8 +81,6 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge);
|
||||
void SetFinish(void);
|
||||
void ResetSetFinish(void);
|
||||
void ResetSetToken(void);
|
||||
bool WaitingForPEInterrupt();
|
||||
void ResumeWaitingForPEInterrupt();
|
||||
|
||||
// Bounding box functionality. Paper Mario (both) are a couple of the few games that use it.
|
||||
extern u16 bbox[4];
|
||||
|
Reference in New Issue
Block a user