1. This should fix Issue 1625 (Bizarre Auto Frame Limit)
Now the frame limiter yields on CPU thread, not as before on GPU thread mistakenly 2. Fixed clear of VI interrupts I guess VI interrupts are not used at all, because they were never cleared before 3. Made GPU thread 0% processor usage when paused whatever your active config is. I tried the event approach but somehow the thread resume latency is excessively long (Who can tell me why?) git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4790 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
64167bcb60
commit
9cbd508181
|
@ -78,7 +78,7 @@ void Timer::Update()
|
|||
// -------------------------------------
|
||||
|
||||
// Get the number of milliseconds since the last Update()
|
||||
s64 Timer::GetTimeDifference()
|
||||
u64 Timer::GetTimeDifference()
|
||||
{
|
||||
return(timeGetTime() - m_LastTime);
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
void Update();
|
||||
|
||||
// The time difference is always returned in milliseconds, regardless of alternative internal representation
|
||||
s64 GetTimeDifference();
|
||||
u64 GetTimeDifference();
|
||||
void AddTimeDifference();
|
||||
void WindBackStartingTime(u64 WindBack);
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#endif
|
||||
|
||||
#include "Setup.h" // Common
|
||||
#include "Atomic.h"
|
||||
#include "Thread.h"
|
||||
#include "Timer.h"
|
||||
#include "Common.h"
|
||||
|
@ -64,11 +65,9 @@
|
|||
namespace Core
|
||||
{
|
||||
|
||||
|
||||
// Declarations and definitions
|
||||
Common::Timer Timer;
|
||||
u32 frames = 0;
|
||||
|
||||
volatile u32 DrawnFrame = 0;
|
||||
|
||||
// Function forwarding
|
||||
//void Callback_VideoRequestWindowSize(int _iWidth, int _iHeight, BOOL _bFullscreen);
|
||||
|
@ -587,102 +586,29 @@ void ScreenShot()
|
|||
{
|
||||
ScreenShot(GenerateScreenshotName());
|
||||
}
|
||||
|
||||
// --- Callbacks for plugins / engine ---
|
||||
|
||||
|
||||
// Callback_VideoLog
|
||||
// WARNING - THIS IS EXECUTED FROM VIDEO THREAD
|
||||
void Callback_VideoLog(const TCHAR *_szMessage, int _bDoBreak)
|
||||
// Apply Frame Limit and Display FPS info
|
||||
// This should only be called from VI
|
||||
void FrameThrottle()
|
||||
{
|
||||
INFO_LOG(VIDEO, _szMessage);
|
||||
}
|
||||
|
||||
// reports if a frame should be skipped or not
|
||||
// depending on the framelimit set
|
||||
bool report_slow(int skipped)
|
||||
{
|
||||
u32 targetfps = SConfig::GetInstance().m_Framelimit * 5;
|
||||
double wait_frametime;
|
||||
u32 TargetFPS = (SConfig::GetInstance().m_Framelimit > 1) ? SConfig::GetInstance().m_Framelimit * 5
|
||||
: VideoInterface::TargetRefreshRate;
|
||||
u32 frames = Common::AtomicLoad(DrawnFrame);
|
||||
|
||||
if (targetfps < 5)
|
||||
wait_frametime = (1000.0 / VideoInterface::TargetRefreshRate);
|
||||
else
|
||||
wait_frametime = (1000.0 / targetfps);
|
||||
|
||||
bool fps_slow;
|
||||
|
||||
if (Timer.GetTimeDifference() < wait_frametime * (frames + skipped))
|
||||
fps_slow=false;
|
||||
else
|
||||
fps_slow=true;
|
||||
|
||||
if (targetfps == 5)
|
||||
fps_slow=true;
|
||||
|
||||
return fps_slow;
|
||||
}
|
||||
|
||||
// Callback_VideoCopiedToXFB
|
||||
// WARNING - THIS IS EXECUTED FROM VIDEO THREAD
|
||||
// We do not write to anything outside this function here
|
||||
void Callback_VideoCopiedToXFB(bool video_update)
|
||||
{
|
||||
if(!video_update)
|
||||
Frame::FrameUpdate();
|
||||
|
||||
SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
|
||||
|
||||
//count FPS and VPS
|
||||
static u32 videoupd = 0;
|
||||
static u32 no_framelimit = 0;
|
||||
|
||||
|
||||
if (video_update)
|
||||
videoupd++;
|
||||
else
|
||||
frames++;
|
||||
|
||||
if (no_framelimit>0)
|
||||
no_framelimit--;
|
||||
|
||||
// Custom frame limiter
|
||||
// --------------------
|
||||
u32 targetfps = SConfig::GetInstance().m_Framelimit * 5;
|
||||
|
||||
if (targetfps > 5)
|
||||
// When frame limit is NOT off
|
||||
if (frames && SConfig::GetInstance().m_Framelimit != 1)
|
||||
{
|
||||
double wait_frametime = (1000.0 / targetfps);
|
||||
|
||||
if (Timer.GetTimeDifference() >= wait_frametime * frames)
|
||||
no_framelimit = (u32)Timer.GetTimeDifference();
|
||||
|
||||
while (Timer.GetTimeDifference() < wait_frametime * frames)
|
||||
{
|
||||
if (no_framelimit == 0)
|
||||
Common::SleepCurrentThread(1);
|
||||
}
|
||||
}
|
||||
else if (targetfps < 5)
|
||||
{
|
||||
double wait_frametime = (1000.0 / VideoInterface::TargetRefreshRate);
|
||||
|
||||
if (Timer.GetTimeDifference() >= wait_frametime * frames)
|
||||
no_framelimit = (u32)Timer.GetTimeDifference();
|
||||
|
||||
while (Timer.GetTimeDifference() < wait_frametime * videoupd)
|
||||
{
|
||||
// TODO : This is wrong, the sleep shouldn't be there but rather in cputhread
|
||||
// as it's not based on the fps but on the refresh rate...
|
||||
if (no_framelimit == 0)
|
||||
Common::SleepCurrentThread(1);
|
||||
}
|
||||
u32 frametime = frames * 1000 / TargetFPS;
|
||||
while (Timer.GetTimeDifference() < frametime)
|
||||
//Common::YieldCPU();
|
||||
Common::SleepCurrentThread(1);
|
||||
}
|
||||
|
||||
if (Timer.GetTimeDifference() >= 1000)
|
||||
// Update info per second
|
||||
u32 ElapseTime = (u32)Timer.GetTimeDifference();
|
||||
if (ElapseTime >= 1000)
|
||||
{
|
||||
// Time passed
|
||||
float t = (float)(Timer.GetTimeDifference()) / 1000.f;
|
||||
SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
|
||||
|
||||
// Use extended or summary information. The summary information does not print the ticks data,
|
||||
// that's more of a debugging interest, it can always be optional of course if someone is interested.
|
||||
|
@ -691,8 +617,8 @@ void Callback_VideoCopiedToXFB(bool video_update)
|
|||
u64 newTicks = CoreTiming::GetTicks();
|
||||
u64 newIdleTicks = CoreTiming::GetIdleTicks();
|
||||
|
||||
s64 diff = (newTicks - ticks) / 1000000;
|
||||
s64 idleDiff = (newIdleTicks - idleTicks) / 1000000;
|
||||
u64 diff = (newTicks - ticks) / 1000000;
|
||||
u64 idleDiff = (newIdleTicks - idleTicks) / 1000000;
|
||||
|
||||
ticks = newTicks;
|
||||
idleTicks = newIdleTicks;
|
||||
|
@ -700,13 +626,9 @@ void Callback_VideoCopiedToXFB(bool video_update)
|
|||
float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100;
|
||||
#endif
|
||||
|
||||
float FPS = (float)frames / t;
|
||||
// for some reasons "VideoInterface::ActualRefreshRate" gives some odd results :(
|
||||
float VPS = (float)videoupd / t;
|
||||
u32 FPS = frames * 1000 / ElapseTime;
|
||||
|
||||
int TargetVPS = (int)(VideoInterface::TargetRefreshRate + 0.5);
|
||||
|
||||
float Speed = ((VPS > 0.0f ? VPS : VideoInterface::ActualRefreshRate) / TargetVPS) * 100.0f;
|
||||
float Speed = (float)FPS / (float)TargetFPS * 100.0f;
|
||||
|
||||
// Settings are shown the same for both extended and summary info
|
||||
std::string SSettings = StringFromFormat(" | Core: %s %s",
|
||||
|
@ -726,8 +648,7 @@ void Callback_VideoCopiedToXFB(bool video_update)
|
|||
_CoreParameter.bCPUThread ? "DC" : "SC");
|
||||
|
||||
#ifdef EXTENDED_INFO
|
||||
std::string SFPS = StringFromFormat("FPS: %4.1f - VPS: %i/%i (%3.0f%%)",
|
||||
FPS, VPS > 0 ? (int)VPS : (int)VideoInterface::ActualRefreshRate, TargetVPS, Speed);
|
||||
std::string SFPS = StringFromFormat("FPS: %i/%i (%3.0f%%)", FPS, TargetFPS, Speed);
|
||||
SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)",
|
||||
_CoreParameter.bSkipIdle ? "~" : "",
|
||||
(int)(diff),
|
||||
|
@ -738,8 +659,7 @@ void Callback_VideoCopiedToXFB(bool video_update)
|
|||
TicksPercentage);
|
||||
|
||||
#else // Summary information
|
||||
std::string SFPS = StringFromFormat("FPS: %4.1f - VPS: %i/%i (%3.0f%%)",
|
||||
FPS, VPS > 0 ? (int)VPS : (int)VideoInterface::ActualRefreshRate, TargetVPS, Speed);
|
||||
std::string SFPS = StringFromFormat("FPS: %i/%i (%3.0f%%)", FPS, TargetFPS, Speed);
|
||||
#endif
|
||||
|
||||
// This is our final "frame counter" string
|
||||
|
@ -752,12 +672,39 @@ void Callback_VideoCopiedToXFB(bool video_update)
|
|||
Host_UpdateStatusBar(SMessage.c_str());
|
||||
|
||||
// Reset frame counter
|
||||
frames = 0;
|
||||
videoupd = 0;
|
||||
Timer.Update();
|
||||
Common::AtomicStore(DrawnFrame, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Executed from GPU thread
|
||||
// reports if a frame should be skipped or not
|
||||
// depending on the framelimit set
|
||||
bool report_slow(int skipped)
|
||||
{
|
||||
u32 TargetFPS = (SConfig::GetInstance().m_Framelimit > 1) ? SConfig::GetInstance().m_Framelimit * 5
|
||||
: VideoInterface::TargetRefreshRate;
|
||||
u32 frames = Common::AtomicLoad(DrawnFrame);
|
||||
bool fps_slow = (Timer.GetTimeDifference() < (frames + skipped) * 1000 / TargetFPS) ? false : true;
|
||||
|
||||
return fps_slow;
|
||||
}
|
||||
|
||||
// --- Callbacks for plugins / engine ---
|
||||
|
||||
// Callback_VideoLog
|
||||
// WARNING - THIS IS EXECUTED FROM VIDEO THREAD
|
||||
void Callback_VideoLog(const TCHAR *_szMessage, int _bDoBreak)
|
||||
{
|
||||
INFO_LOG(VIDEO, _szMessage);
|
||||
}
|
||||
|
||||
// Should be called from GPU thread when a frame is drawn
|
||||
void Callback_VideoCopiedToXFB(bool video_update)
|
||||
{
|
||||
Common::AtomicIncrement(DrawnFrame);
|
||||
Frame::FrameUpdate();
|
||||
}
|
||||
|
||||
// Callback_DSPLog
|
||||
// WARNING - THIS MAY BE EXECUTED FROM DSP THREAD
|
||||
|
@ -835,7 +782,8 @@ void Callback_WiimoteLog(const TCHAR* _szMessage, int _v)
|
|||
}
|
||||
|
||||
// TODO: Get rid of at some point
|
||||
const SCoreStartupParameter& GetStartupParameter() {
|
||||
const SCoreStartupParameter& GetStartupParameter()
|
||||
{
|
||||
return SConfig::GetInstance().m_LocalCoreStartupParameter;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ namespace Core
|
|||
void StopTrace();
|
||||
|
||||
bool report_slow(int skipped);
|
||||
void FrameThrottle();
|
||||
|
||||
// -----------------------------------------
|
||||
#ifdef RERECORDING
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
#include "ChunkFile.h"
|
||||
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
|
||||
#include "../Core.h" // <- for Core::GetStartupParameter().bUseDualCore
|
||||
#include "../Core.h"
|
||||
#include "ProcessorInterface.h"
|
||||
#include "VideoInterface.h"
|
||||
#include "Memmap.h"
|
||||
|
@ -28,7 +27,6 @@
|
|||
#include "../CoreTiming.h"
|
||||
#include "../HW/SystemTimers.h"
|
||||
#include "StringUtil.h"
|
||||
#include "Timer.h"
|
||||
|
||||
namespace VideoInterface
|
||||
{
|
||||
|
@ -53,7 +51,7 @@ enum
|
|||
VI_FB_LEFT_TOP_LO = 0x1e,
|
||||
VI_FB_RIGHT_TOP_HI = 0x20, // FB_RIGHT_TOP is only used in 3D mode
|
||||
VI_FB_RIGHT_TOP_LO = 0x22,
|
||||
VI_FB_LEFT_BOTTOM_HI = 0x24, // FB_LEFT_TOP is second half of XFB info
|
||||
VI_FB_LEFT_BOTTOM_HI = 0x24, // FB_LEFT_BOTTOM is second half of XFB info
|
||||
VI_FB_LEFT_BOTTOM_LO = 0x26,
|
||||
VI_FB_RIGHT_BOTTOM_HI = 0x28, // FB_RIGHT_BOTTOM is only used in 3D mode
|
||||
VI_FB_RIGHT_BOTTOM_LO = 0x2a,
|
||||
|
@ -268,6 +266,7 @@ union UVIFilterCoefTable3
|
|||
unsigned : 2;
|
||||
};
|
||||
};
|
||||
|
||||
// Used for tables 3-6
|
||||
union UVIFilterCoefTable4
|
||||
{
|
||||
|
@ -281,6 +280,7 @@ union UVIFilterCoefTable4
|
|||
unsigned Tap3 : 8;
|
||||
};
|
||||
};
|
||||
|
||||
struct SVIFilterCoefTables
|
||||
{
|
||||
UVIFilterCoefTable3 Tables02[3];
|
||||
|
@ -331,16 +331,13 @@ static UVIBorderBlankRegister m_BorderHBlank;
|
|||
// 0xcc002076 - 0xcc00207f is full of 0x00FF: unknown
|
||||
// 0xcc002080 - 0xcc002100 even more unknown
|
||||
|
||||
u32 TargetRefreshRate = 0;
|
||||
|
||||
static u32 TicksPerFrame = 0;
|
||||
static u32 s_lineCount = 0;
|
||||
static u32 s_upperFieldBegin = 0;
|
||||
static u32 s_lowerFieldBegin = 0;
|
||||
|
||||
float TargetRefreshRate = 0.0;
|
||||
float ActualRefreshRate = 0.0;
|
||||
s64 SyncTicksProgress = 0;
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(m_VerticalTimingRegister);
|
||||
|
@ -367,7 +364,7 @@ void DoState(PointerWrap &p)
|
|||
p.Do(m_DTVStatus);
|
||||
p.Do(m_FBWidth);
|
||||
p.Do(m_BorderHBlank);
|
||||
|
||||
p.Do(TargetRefreshRate);
|
||||
p.Do(TicksPerFrame);
|
||||
p.Do(s_lineCount);
|
||||
p.Do(s_upperFieldBegin);
|
||||
|
@ -376,11 +373,6 @@ void DoState(PointerWrap &p)
|
|||
|
||||
void PreInit(bool _bNTSC)
|
||||
{
|
||||
TicksPerFrame = 0;
|
||||
s_lineCount = 0;
|
||||
s_upperFieldBegin = 0;
|
||||
s_lowerFieldBegin = 0;
|
||||
|
||||
m_VerticalTimingRegister.EQU = 6;
|
||||
|
||||
m_DisplayControlRegister.ENB = 1;
|
||||
|
@ -439,9 +431,7 @@ void Init()
|
|||
|
||||
m_DisplayControlRegister.Hex = 0;
|
||||
|
||||
s_lineCount = 0;
|
||||
s_upperFieldBegin = 0;
|
||||
s_lowerFieldBegin = 0;
|
||||
UpdateTiming();
|
||||
}
|
||||
|
||||
void Read8(u8& _uReturnValue, const u32 _iAddress)
|
||||
|
@ -711,9 +701,12 @@ void Write16(const u16 _iValue, const u32 _iAddress)
|
|||
{
|
||||
// shuffle2 clear all data, reset to default vals, and enter idle mode
|
||||
m_DisplayControlRegister.RST = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
m_InterruptRegister[i].Hex = 0;
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
UpdateTiming();
|
||||
UpdateTiming();
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -802,38 +795,38 @@ void Write16(const u16 _iValue, const u32 _iAddress)
|
|||
// RETRACE STUFF ...
|
||||
case VI_PRERETRACE_HI:
|
||||
m_InterruptRegister[0].Hi = _iValue;
|
||||
m_InterruptRegister[0].IR_INT = 0;
|
||||
UpdateInterrupts();
|
||||
break;
|
||||
case VI_PRERETRACE_LO:
|
||||
m_InterruptRegister[0].Lo = _iValue;
|
||||
UpdateInterrupts();
|
||||
break;
|
||||
|
||||
case VI_POSTRETRACE_HI:
|
||||
m_InterruptRegister[1].Hi = _iValue;
|
||||
m_InterruptRegister[1].IR_INT = 0;
|
||||
UpdateInterrupts();
|
||||
break;
|
||||
case VI_POSTRETRACE_LO:
|
||||
m_InterruptRegister[1].Lo = _iValue;
|
||||
UpdateInterrupts();
|
||||
break;
|
||||
|
||||
case VI_DISPLAY_INTERRUPT_2_HI:
|
||||
m_InterruptRegister[2].Hi = _iValue;
|
||||
m_InterruptRegister[2].IR_INT = 0;
|
||||
UpdateInterrupts();
|
||||
break;
|
||||
case VI_DISPLAY_INTERRUPT_2_LO:
|
||||
m_InterruptRegister[2].Lo = _iValue;
|
||||
UpdateInterrupts();
|
||||
break;
|
||||
|
||||
case VI_DISPLAY_INTERRUPT_3_HI:
|
||||
m_InterruptRegister[3].Hi = _iValue;
|
||||
m_InterruptRegister[3].IR_INT = 0;
|
||||
UpdateInterrupts();
|
||||
break;
|
||||
case VI_DISPLAY_INTERRUPT_3_LO:
|
||||
m_InterruptRegister[3].Lo = _iValue;
|
||||
UpdateInterrupts();
|
||||
break;
|
||||
|
||||
case VI_DISPLAY_LATCH_0_HI:
|
||||
|
@ -988,46 +981,22 @@ u32 GetXFBAddressBottom()
|
|||
return m_XFBInfoBottom.FBB;
|
||||
}
|
||||
|
||||
|
||||
// NTSC is 60 FPS, right?
|
||||
// Wrong, it's about 59.94 FPS. The NTSC engineers had to slightly lower
|
||||
// the field rate from 60 FPS when they added color to the standard.
|
||||
// This was done to prevent analog interference between the video and
|
||||
// audio signals. PAL has no similar reduction; it is exactly 50 FPS.
|
||||
const double NTSC_FIELD_RATE = 60.0 / 1.001;
|
||||
const u32 NTSC_LINE_COUNT = 525;
|
||||
// These line numbers indicate the beginning of the "active video" in a frame.
|
||||
// An NTSC frame has the lower field first followed by the upper field.
|
||||
// TODO: Is this true for PAL-M? Is this true for EURGB60?
|
||||
const u32 NTSC_LOWER_BEGIN = 21;
|
||||
const u32 NTSC_UPPER_BEGIN = 283;
|
||||
|
||||
const double PAL_FIELD_RATE = 50.0;
|
||||
const u32 PAL_LINE_COUNT = 625;
|
||||
// These line numbers indicate the beginning of the "active video" in a frame.
|
||||
// A PAL frame has the upper field first followed by the lower field.
|
||||
const u32 PAL_UPPER_BEGIN = 23; // TODO: Actually 23.5!
|
||||
const u32 PAL_LOWER_BEGIN = 336;
|
||||
|
||||
// Screenshot and screen message
|
||||
void UpdateTiming()
|
||||
{
|
||||
switch (m_DisplayControlRegister.FMT)
|
||||
{
|
||||
|
||||
case 0: // NTSC
|
||||
case 2: // PAL-M
|
||||
|
||||
TicksPerFrame = (u32)(SystemTimers::GetTicksPerSecond() / (NTSC_FIELD_RATE / 2.0));
|
||||
TargetRefreshRate = NTSC_FIELD_RATE;
|
||||
TicksPerFrame = SystemTimers::GetTicksPerSecond() / (NTSC_FIELD_RATE / 2);
|
||||
s_lineCount = m_DisplayControlRegister.NIN ? (NTSC_LINE_COUNT+1)/2 : NTSC_LINE_COUNT;
|
||||
// TODO: The game may have some control over these parameters (not that it's useful).
|
||||
s_upperFieldBegin = NTSC_UPPER_BEGIN;
|
||||
s_lowerFieldBegin = NTSC_LOWER_BEGIN;
|
||||
break;
|
||||
|
||||
case 1: // PAL
|
||||
|
||||
TicksPerFrame = (u32)(SystemTimers::GetTicksPerSecond() / (PAL_FIELD_RATE / 2.0));
|
||||
TargetRefreshRate = PAL_FIELD_RATE;
|
||||
TicksPerFrame = SystemTimers::GetTicksPerSecond() / (PAL_FIELD_RATE / 2);
|
||||
s_lineCount = m_DisplayControlRegister.NIN ? (PAL_LINE_COUNT+1)/2 : PAL_LINE_COUNT;
|
||||
s_upperFieldBegin = PAL_UPPER_BEGIN;
|
||||
s_lowerFieldBegin = PAL_LOWER_BEGIN;
|
||||
|
@ -1040,7 +1009,6 @@ void UpdateTiming()
|
|||
default:
|
||||
PanicAlert("Unknown Video Format - CVideoInterface");
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1056,7 +1024,6 @@ int GetTicksPerFrame()
|
|||
return TicksPerFrame;
|
||||
}
|
||||
|
||||
|
||||
static void BeginField(FieldType field)
|
||||
{
|
||||
u32 fbWidth = m_HorizontalStepping.FieldSteps * 16;
|
||||
|
@ -1088,45 +1055,24 @@ static void EndField()
|
|||
}
|
||||
|
||||
|
||||
// Purpose 1: Send VI interrupt for every screen refresh
|
||||
// Purpose 2: Execute XFB copy in homebrew games
|
||||
// Run when: This is run 15700 times per second on full speed
|
||||
// Purpose: Send VI interrupt when triggered
|
||||
// Run when: When every line is scaned
|
||||
void Update()
|
||||
{
|
||||
// Update the target refresh rate
|
||||
TargetRefreshRate = (float)((m_DisplayControlRegister.FMT == 0 || m_DisplayControlRegister.FMT == 2)
|
||||
? NTSC_FIELD_RATE : PAL_FIELD_RATE);
|
||||
|
||||
// Calculate actual refresh rate
|
||||
static u64 LastTick = 0;
|
||||
static s64 UpdateCheck = timeGetTime() + 1000, TickProgress = 0;
|
||||
s64 curTime = timeGetTime();
|
||||
if (UpdateCheck < (int)curTime)
|
||||
{
|
||||
UpdateCheck = curTime + 1000;
|
||||
TickProgress = CoreTiming::GetTicks() - LastTick;
|
||||
// Calculated CPU-GPU synced ticks for the dual core mode too
|
||||
// NOTICE_LOG(VIDEO, "Removed: %s Mhz", ThS(SyncTicksProgress / 1000000, false).c_str());
|
||||
SyncTicksProgress += TickProgress;
|
||||
// Multipled by two because of the way TicksPerFrame is calculated (divided by 25 and 30
|
||||
// rather than 50 and 60)
|
||||
|
||||
ActualRefreshRate = (float)(((double)SyncTicksProgress / (double)TicksPerFrame) * 2.0);
|
||||
LastTick = CoreTiming::GetTicks();
|
||||
SyncTicksProgress = 0;
|
||||
}
|
||||
|
||||
// TODO: What's the correct behavior for progressive mode?
|
||||
|
||||
if (m_VBeamPos == s_upperFieldBegin + m_VerticalTimingRegister.ACV)
|
||||
EndField();
|
||||
|
||||
if (m_VBeamPos == s_lowerFieldBegin + m_VerticalTimingRegister.ACV)
|
||||
else if (m_VBeamPos == s_lowerFieldBegin + m_VerticalTimingRegister.ACV)
|
||||
EndField();
|
||||
|
||||
m_VBeamPos++;
|
||||
if (m_VBeamPos > s_lineCount)
|
||||
|
||||
if (++m_VBeamPos > s_lineCount)
|
||||
{
|
||||
m_VBeamPos = 1;
|
||||
// Apply frame throttle wheneven a full screen scan finishes
|
||||
Core::FrameThrottle();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
|
@ -1135,11 +1081,12 @@ void Update()
|
|||
}
|
||||
UpdateInterrupts();
|
||||
|
||||
|
||||
if (m_VBeamPos == s_upperFieldBegin)
|
||||
BeginField(m_DisplayControlRegister.NIN ? FIELD_PROGRESSIVE : FIELD_UPPER);
|
||||
|
||||
if (m_VBeamPos == s_lowerFieldBegin)
|
||||
else if (m_VBeamPos == s_lowerFieldBegin)
|
||||
BeginField(m_DisplayControlRegister.NIN ? FIELD_PROGRESSIVE : FIELD_LOWER);
|
||||
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -22,6 +22,31 @@ class PointerWrap;
|
|||
|
||||
namespace VideoInterface
|
||||
{
|
||||
// NTSC is 60 FPS, right?
|
||||
// Wrong, it's about 59.94 FPS. The NTSC engineers had to slightly lower
|
||||
// the field rate from 60 FPS when they added color to the standard.
|
||||
// This was done to prevent analog interference between the video and
|
||||
// audio signals. PAL has no similar reduction; it is exactly 50 FPS.
|
||||
//#define NTSC_FIELD_RATE (60.0f / 1.001f)
|
||||
#define NTSC_FIELD_RATE 60
|
||||
#define NTSC_LINE_COUNT 525
|
||||
// These line numbers indicate the beginning of the "active video" in a frame.
|
||||
// An NTSC frame has the lower field first followed by the upper field.
|
||||
// TODO: Is this true for PAL-M? Is this true for EURGB60?
|
||||
#define NTSC_LOWER_BEGIN 21
|
||||
#define NTSC_UPPER_BEGIN 283
|
||||
|
||||
//#define PAL_FIELD_RATE 50.0f
|
||||
#define PAL_FIELD_RATE 50
|
||||
#define PAL_LINE_COUNT 625
|
||||
// These line numbers indicate the beginning of the "active video" in a frame.
|
||||
// A PAL frame has the upper field first followed by the lower field.
|
||||
#define PAL_UPPER_BEGIN 23 // TODO: Actually 23.5!
|
||||
#define PAL_LOWER_BEGIN 336
|
||||
|
||||
// urgh, ugly externs.
|
||||
extern u32 TargetRefreshRate;
|
||||
|
||||
// For BS2 HLE
|
||||
void PreInit(bool _bNTSC);
|
||||
void SetRegionReg(char _region);
|
||||
|
@ -43,11 +68,6 @@ namespace VideoInterface
|
|||
// Update and draw framebuffer(s)
|
||||
void Update();
|
||||
|
||||
// urgh, ugly externs.
|
||||
extern float ActualRefreshRate;
|
||||
extern float TargetRefreshRate;
|
||||
extern s64 SyncTicksProgress;
|
||||
|
||||
// UpdateInterrupts: check if we have to generate a new VI Interrupt
|
||||
void UpdateInterrupts();
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ u32 g_autoFirstKey = 0, g_autoSecondKey = 0;
|
|||
bool g_bFirstKey = true;
|
||||
PlayMode g_playMode = MODE_NONE;
|
||||
|
||||
int g_framesToSkip = 0, g_frameSkipCounter = 0;
|
||||
unsigned int g_framesToSkip = 0, g_frameSkipCounter = 0;
|
||||
|
||||
int g_numPads = 0;
|
||||
ControllerState *g_padStates;
|
||||
|
@ -70,14 +70,13 @@ void FrameUpdate() {
|
|||
EndPlayInput();
|
||||
}
|
||||
|
||||
|
||||
g_bPolled = false;
|
||||
}
|
||||
|
||||
void SetFrameSkipping(unsigned int framesToSkip) {
|
||||
cs_frameSkip.Enter();
|
||||
|
||||
g_framesToSkip = (int)framesToSkip;
|
||||
g_framesToSkip = framesToSkip;
|
||||
g_frameSkipCounter = 0;
|
||||
|
||||
// Don't forget to re-enable rendering in case it wasn't...
|
||||
|
|
|
@ -51,7 +51,9 @@ extern bool g_bFrameStep, g_bAutoFire, g_bFirstKey, g_bPolled;
|
|||
extern u32 g_autoFirstKey, g_autoSecondKey;
|
||||
extern PlayMode g_playMode;
|
||||
|
||||
extern int g_framesToSkip, g_frameSkipCounter, g_numPads;
|
||||
extern unsigned int g_framesToSkip, g_frameSkipCounter;
|
||||
|
||||
extern int g_numPads;
|
||||
extern ControllerState *g_padStates;
|
||||
extern FILE *g_recordfd;
|
||||
extern std::string g_recordFile;
|
||||
|
|
|
@ -383,7 +383,6 @@ void Write16(const u16 _Value, const u32 _Address)
|
|||
// Touching that game is a no-go so I don't want to take the risk :p
|
||||
while (fifo.bFF_GPReadEnable && ((!fifo.bFF_BPEnable && fifo.CPReadWriteDistance) || (fifo.bFF_BPEnable && !fifo.bFF_Breakpoint)))
|
||||
{
|
||||
Fifo_RunLoop();
|
||||
s_fifoIdleEvent.MsgWait();
|
||||
}
|
||||
}
|
||||
|
@ -414,8 +413,6 @@ void Write16(const u16 _Value, const u32 _Address)
|
|||
Common::AtomicStore(fifo.bFF_Breakpoint, 0);
|
||||
}
|
||||
|
||||
Fifo_RunLoop();
|
||||
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to CTRL_REGISTER : %04x", _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR, "\t GPREAD %s | LINK %s | BP %s || Init %s | OvF %s | UndF %s"
|
||||
, fifo.bFF_GPReadEnable ? "ON" : "OFF"
|
||||
|
@ -572,10 +569,9 @@ void WaitForFrameFinish()
|
|||
{
|
||||
while ((fake_GPWatchdogLastToken == fifo.Fake_GPWDToken) && fifo.bFF_GPReadEnable && ((!fifo.bFF_BPEnable && fifo.CPReadWriteDistance) || (fifo.bFF_BPEnable && !fifo.bFF_Breakpoint)));
|
||||
{
|
||||
Fifo_RunLoop();
|
||||
s_fifoIdleEvent.MsgWait();
|
||||
}
|
||||
|
||||
|
||||
fake_GPWatchdogLastToken = fifo.Fake_GPWDToken;
|
||||
}
|
||||
|
||||
|
@ -594,7 +590,6 @@ void STACKALIGN GatherPipeBursted()
|
|||
fifo.CPWritePointer += GATHER_PIPE_SIZE;
|
||||
|
||||
Common::AtomicAdd(fifo.CPReadWriteDistance, GATHER_PIPE_SIZE);
|
||||
Fifo_RunLoop();
|
||||
|
||||
// High watermark overflow handling (hacked way)
|
||||
if (fifo.CPReadWriteDistance > fifo.CPHiWatermark)
|
||||
|
@ -619,7 +614,6 @@ void STACKALIGN GatherPipeBursted()
|
|||
// Wait for GPU to catch up
|
||||
while (fifo.CPReadWriteDistance > fifo.CPLoWatermark && fifo.bFF_GPReadEnable && (!fifo.bFF_BPEnable || (fifo.bFF_BPEnable && !fifo.bFF_Breakpoint)))
|
||||
{
|
||||
Fifo_RunLoop();
|
||||
s_fifoIdleEvent.MsgWait();
|
||||
}
|
||||
}
|
||||
|
@ -725,7 +719,6 @@ void UpdateFifoRegister()
|
|||
dist = (wp - fifo.CPBase) + ((fifo.CPEnd + GATHER_PIPE_SIZE) - rp);
|
||||
|
||||
Common::AtomicStore(fifo.CPReadWriteDistance, dist);
|
||||
Fifo_RunLoop();
|
||||
|
||||
if (!g_VideoInitialize.bOnThread)
|
||||
CatchUpGPU();
|
||||
|
|
|
@ -34,6 +34,7 @@ extern u8* g_pVideoData;
|
|||
namespace
|
||||
{
|
||||
static volatile bool fifoStateRun = false;
|
||||
static volatile bool EmuRunning = false;
|
||||
static u8 *videoBuffer;
|
||||
static Common::Event fifo_run_event;
|
||||
// STATE_TO_SAVE
|
||||
|
@ -100,9 +101,11 @@ void Fifo_ExitLoopNonBlocking()
|
|||
fifo_run_event.Set();
|
||||
}
|
||||
|
||||
void Fifo_RunLoop()
|
||||
void Fifo_RunLoop(bool run)
|
||||
{
|
||||
fifo_run_event.Set();
|
||||
EmuRunning = run;
|
||||
if (run)
|
||||
fifo_run_event.Set();
|
||||
}
|
||||
|
||||
// Description: Fifo_EnterLoop() sends data through this function.
|
||||
|
@ -210,9 +213,7 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||
}
|
||||
|
||||
CommandProcessor::SetFifoIdleFromVideoPlugin();
|
||||
// "VideoFifo_CheckEFBAccess()" & "VideoFifo_CheckSwapRequest()" should be
|
||||
// moved to a more suitable place than inside function "Fifo_EnterLoop()"
|
||||
if (g_ActiveConfig.bEFBAccessEnable || g_ActiveConfig.bUseXFB)
|
||||
if (EmuRunning)
|
||||
Common::YieldCPU();
|
||||
else
|
||||
fifo_run_event.MsgWait();
|
||||
|
|
|
@ -36,7 +36,7 @@ void Fifo_SendFifoData(u8* _uData, u32 len);
|
|||
void Fifo_EnterLoop(const SVideoInitialize &video_initialize);
|
||||
void Fifo_ExitLoop();
|
||||
void Fifo_ExitLoopNonBlocking();
|
||||
void Fifo_RunLoop();
|
||||
void Fifo_RunLoop(bool run);
|
||||
|
||||
void Fifo_DoState(PointerWrap &f);
|
||||
|
||||
|
|
|
@ -535,6 +535,7 @@ void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRect
|
|||
DEBUGGER_PAUSE_LOG_AT(NEXT_XFB_CMD,false,{printf("RenderToXFB - disabled");});
|
||||
return;
|
||||
}
|
||||
|
||||
Renderer::ResetAPIState();
|
||||
// Set the backbuffer as the rendering target
|
||||
D3D::dev->SetDepthStencilSurface(NULL);
|
||||
|
@ -543,7 +544,6 @@ void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRect
|
|||
D3DDumpFrame();
|
||||
EFBTextureToD3DBackBuffer(sourceRc);
|
||||
D3D::EndFrame();
|
||||
|
||||
|
||||
DEBUGGER_LOG_AT((NEXT_XFB_CMD|NEXT_EFB_CMD|NEXT_FRAME),
|
||||
{printf("StretchRect, EFB->XFB\n");});
|
||||
|
@ -553,6 +553,7 @@ void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRect
|
|||
xfbAddr, fbWidth, fbHeight,
|
||||
sourceRc.left, sourceRc.top, sourceRc.right, sourceRc.bottom);}
|
||||
);
|
||||
|
||||
Swap(0,FIELD_PROGRESSIVE,0,0); // we used to swap the buffer here, now we will wait
|
||||
// until the XFB pointer is updated by VI
|
||||
D3D::BeginFrame();
|
||||
|
@ -959,9 +960,9 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
|
|||
// Make any new configuration settings active.
|
||||
UpdateActiveConfig();
|
||||
|
||||
//TODO: Resize backbuffer if window size has changed. This code crashes, debug it.
|
||||
g_VideoInitialize.pCopiedToXFB(false);
|
||||
|
||||
//TODO: Resize backbuffer if window size has changed. This code crashes, debug it.
|
||||
CheckForResize();
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
|
|
@ -312,6 +312,7 @@ void DoState(unsigned char **ptr, int mode) {
|
|||
|
||||
void EmuStateChange(PLUGIN_EMUSTATE newState)
|
||||
{
|
||||
Fifo_RunLoop((newState == PLUGIN_EMUSTATE_PLAY) ? true : false);
|
||||
}
|
||||
|
||||
void Video_EnterLoop()
|
||||
|
@ -333,7 +334,7 @@ void Video_SetRendering(bool bEnabled) {
|
|||
// Run from the graphics thread
|
||||
void VideoFifo_CheckSwapRequest()
|
||||
{
|
||||
// CPU swap, not finished, seems to be working fine for dual-core for now
|
||||
// swap unimplemented
|
||||
return;
|
||||
|
||||
if (s_swapRequested)
|
||||
|
@ -351,12 +352,15 @@ void VideoFifo_CheckSwapRequest()
|
|||
// Run from the graphics thread
|
||||
void VideoFifo_CheckSwapRequestAt(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
// CPU swap unimplemented
|
||||
// swap unimplemented
|
||||
}
|
||||
|
||||
// Run from the CPU thread (from VideoInterface.cpp)
|
||||
void Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
// swap unimplemented
|
||||
return;
|
||||
|
||||
s_beginFieldArgs.xfbAddr = xfbAddr;
|
||||
s_beginFieldArgs.field = field;
|
||||
s_beginFieldArgs.fbWidth = fbWidth;
|
||||
|
@ -365,14 +369,11 @@ void Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
|
|||
|
||||
if (s_initialized)
|
||||
{
|
||||
|
||||
// Make sure previous swap request has made it to the screen
|
||||
if (g_VideoInitialize.bOnThread)
|
||||
{
|
||||
// It seems to be working fine in this way for now without using AtomicLoadAcquire
|
||||
// ector, please check here
|
||||
//while (Common::AtomicLoadAcquire(s_swapRequested))
|
||||
// Common::YieldCPU();
|
||||
//Common::YieldCPU();
|
||||
}
|
||||
else
|
||||
VideoFifo_CheckSwapRequest();
|
||||
|
|
|
@ -597,6 +597,9 @@ void Renderer::SetBlendMode(bool forceUpdate)
|
|||
|
||||
u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
|
||||
{
|
||||
if(!g_ActiveConfig.bEFBAccessEnable)
|
||||
return 0;
|
||||
|
||||
// Get the rectangular target region covered by the EFB pixel.
|
||||
EFBRectangle efbPixelRc;
|
||||
efbPixelRc.left = x;
|
||||
|
|
|
@ -379,6 +379,7 @@ void DoState(unsigned char **ptr, int mode) {
|
|||
|
||||
void EmuStateChange(PLUGIN_EMUSTATE newState)
|
||||
{
|
||||
Fifo_RunLoop((newState == PLUGIN_EMUSTATE_PLAY) ? true : false);
|
||||
}
|
||||
|
||||
// This is called after Video_Initialize() from the Core
|
||||
|
@ -494,9 +495,6 @@ void VideoFifo_CheckSwapRequest()
|
|||
g_VideoInitialize.pCopiedToXFB(false);
|
||||
}
|
||||
|
||||
// TODO : This just updates the frame counter, so we may change this func's name as well
|
||||
g_VideoInitialize.pCopiedToXFB(true);
|
||||
|
||||
Common::AtomicStoreRelease(s_swapRequested, FALSE);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue