--- /dev/null
+/***************************************************************************\r
+ fps.c - description\r
+ -------------------\r
+ begin : Sun Mar 08 2009\r
+ copyright : (C) 1999-2009 by Pete Bernert\r
+ web : www.pbernert.com \r
+ ***************************************************************************/\r
+\r
+/***************************************************************************\r
+ * *\r
+ * This program is free software; you can redistribute it and/or modify *\r
+ * it under the terms of the GNU General Public License as published by *\r
+ * the Free Software Foundation; either version 2 of the License, or *\r
+ * (at your option) any later version. See also the license.txt file for *\r
+ * additional informations. *\r
+ * *\r
+ ***************************************************************************/\r
+\r
+//*************************************************************************// \r
+// History of changes:\r
+//\r
+// 2009/03/08 - Pete \r
+// - generic cleanup for the Peops release\r
+//\r
+//*************************************************************************// \r
+\r
+#ifdef _WINDOWS\r
+#include "Stdafx.h"\r
+#include "Externals.h"\r
+#include "plugin.h"\r
+#include "Fps.h"\r
+#include "Prim.h"\r
+#else\r
+#include "gpuStdafx.h"\r
+#include "gpuExternals.h"\r
+//#include "plugins.h"\r
+#include "gpuFps.h"\r
+#include "gpuPrim.h"\r
+#endif\r
+\r
+#define _IN_FPS\r
+\r
+#define CALLBACK\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// FPS stuff\r
+////////////////////////////////////////////////////////////////////////\r
+#ifdef _WINDOWS\r
+LARGE_INTEGER liCPUFrequency;\r
+#endif\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// FPS skipping / limit\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+BOOL bIsPerformanceCounter;\r
+float fFrameRateHz;\r
+DWORD dwFrameRateTicks;\r
+float fFrameRate;\r
+int iFrameLimit;\r
+BOOL bUseFrameLimit;\r
+BOOL bUseFrameSkip;\r
+DWORD dwLaceCnt;\r
+\r
+BOOL bInitCap; \r
+float fps_skip;\r
+float fps_cur;\r
+\r
+#ifdef _WINDOWS\r
+\r
+void FrameCap (void)\r
+{\r
+ static DWORD curticks, lastticks, _ticks_since_last_update;\r
+ static DWORD TicksToWait = 0;\r
+ static LARGE_INTEGER CurrentTime;\r
+ static LARGE_INTEGER LastTime;\r
+ static BOOL SkipNextWait = FALSE;\r
+ BOOL Waiting = TRUE;\r
+\r
+ //---------------------------------------------------------\r
+ // init some static vars... \r
+ // bInitCap is TRUE on startup and everytime the user\r
+ // is toggling the frame limit\r
+ //---------------------------------------------------------\r
+\r
+ if(bInitCap)\r
+ {\r
+ bInitCap=FALSE;\r
+ if (bIsPerformanceCounter)\r
+ QueryPerformanceCounter(&LastTime);\r
+ lastticks = timeGetTime();\r
+ TicksToWait=0;\r
+ return;\r
+ }\r
+\r
+ //---------------------------------------------------------\r
+\r
+ if(bIsPerformanceCounter)\r
+ {\r
+ QueryPerformanceCounter(&CurrentTime);\r
+ _ticks_since_last_update = CurrentTime.LowPart - LastTime.LowPart;\r
+\r
+ //---------------------------------------------------------\r
+ // check if diff > 1/2 sec, if yes: take mm timer value\r
+ //---------------------------------------------------------\r
+\r
+ curticks = timeGetTime();\r
+ if(_ticks_since_last_update>(liCPUFrequency.LowPart>>1)) \r
+ {\r
+ if(curticks < lastticks)\r
+ _ticks_since_last_update = dwFrameRateTicks+TicksToWait+1;\r
+ else _ticks_since_last_update = (liCPUFrequency.LowPart * (curticks - lastticks))/1000;\r
+ }\r
+\r
+ //---------------------------------------------------------\r
+\r
+ if ((_ticks_since_last_update > TicksToWait) || \r
+ (CurrentTime.LowPart < LastTime.LowPart))\r
+ {\r
+ LastTime.HighPart = CurrentTime.HighPart;\r
+ LastTime.LowPart = CurrentTime.LowPart;\r
+\r
+ lastticks=curticks;\r
+\r
+ if((_ticks_since_last_update-TicksToWait) > dwFrameRateTicks)\r
+ TicksToWait=0;\r
+ else TicksToWait=dwFrameRateTicks-(_ticks_since_last_update-TicksToWait);\r
+ }\r
+ else\r
+ {\r
+ while (Waiting)\r
+ {\r
+ QueryPerformanceCounter(&CurrentTime);\r
+ _ticks_since_last_update = CurrentTime.LowPart - LastTime.LowPart;\r
+\r
+ //---------------------------------------------------------\r
+ // check if diff > 1/2 sec, if yes: take mm timer value\r
+ //---------------------------------------------------------\r
+ curticks = timeGetTime();\r
+ if(_ticks_since_last_update>(liCPUFrequency.LowPart>>1)) \r
+ {\r
+ if(curticks < lastticks)\r
+ _ticks_since_last_update = TicksToWait+1;\r
+ else _ticks_since_last_update = (liCPUFrequency.LowPart * (curticks - lastticks))/1000;\r
+ }\r
+ //---------------------------------------------------------\r
+\r
+ if ((_ticks_since_last_update > TicksToWait) || \r
+ (CurrentTime.LowPart < LastTime.LowPart))\r
+ {\r
+ Waiting = FALSE;\r
+\r
+ lastticks=curticks;\r
+\r
+ LastTime.HighPart = CurrentTime.HighPart;\r
+ LastTime.LowPart = CurrentTime.LowPart;\r
+ TicksToWait = dwFrameRateTicks;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ curticks = timeGetTime();\r
+ _ticks_since_last_update = curticks - lastticks;\r
+\r
+ if ((_ticks_since_last_update > TicksToWait) || \r
+ (curticks < lastticks))\r
+ {\r
+ lastticks = curticks;\r
+\r
+ if((_ticks_since_last_update-TicksToWait) > dwFrameRateTicks)\r
+ TicksToWait=0;\r
+ else TicksToWait=dwFrameRateTicks-(_ticks_since_last_update-TicksToWait);\r
+ }\r
+ else\r
+ {\r
+ while (Waiting)\r
+ {\r
+ curticks = timeGetTime();\r
+ _ticks_since_last_update = curticks - lastticks;\r
+ if ((_ticks_since_last_update > TicksToWait) ||\r
+ (curticks < lastticks))\r
+ {\r
+ Waiting = FALSE;\r
+ lastticks = curticks;\r
+ TicksToWait = dwFrameRateTicks;\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#define MAXSKIP 120\r
+#define MAXLACE 16\r
+\r
+void FrameSkip(void)\r
+{\r
+ static int iNumSkips=0,iAdditionalSkip=0; // number of additional frames to skip\r
+ static DWORD dwLastLace=0; // helper var for frame limitation\r
+ static DWORD curticks, lastticks, _ticks_since_last_update;\r
+ static LARGE_INTEGER CurrentTime;\r
+ static LARGE_INTEGER LastTime;\r
+\r
+ if(!dwLaceCnt) return; // important: if no updatelace happened, we ignore it completely\r
+\r
+ if(iNumSkips) // we are in skipping mode?\r
+ {\r
+ dwLastLace+=dwLaceCnt; // -> calc frame limit helper (number of laces)\r
+ bSkipNextFrame = TRUE; // -> we skip next frame\r
+ iNumSkips--; // -> ok, one done\r
+ }\r
+ else // ok, no additional skipping has to be done... \r
+ { // we check now, if some limitation is needed, or a new skipping has to get started\r
+ DWORD dwWaitTime;\r
+\r
+ if(bInitCap || bSkipNextFrame) // first time or we skipped before?\r
+ {\r
+ if(bUseFrameLimit && !bInitCap) // frame limit wanted and not first time called?\r
+ {\r
+ DWORD dwT=_ticks_since_last_update; // -> that's the time of the last drawn frame\r
+ dwLastLace+=dwLaceCnt; // -> and that's the number of updatelace since the start of the last drawn frame\r
+\r
+ if(bIsPerformanceCounter) // -> now we calc the time of the last drawn frame + the time we spent skipping\r
+ {\r
+ QueryPerformanceCounter(&CurrentTime);\r
+ _ticks_since_last_update= dwT+CurrentTime.LowPart - LastTime.LowPart;\r
+ }\r
+ else\r
+ {\r
+ curticks = timeGetTime();\r
+ _ticks_since_last_update= dwT+curticks - lastticks;\r
+ }\r
+\r
+ dwWaitTime=dwLastLace*dwFrameRateTicks; // -> and now we calc the time the real psx would have needed\r
+\r
+ if(_ticks_since_last_update<dwWaitTime) // -> we were too fast?\r
+ { \r
+ if((dwWaitTime-_ticks_since_last_update)> // -> some more security, to prevent\r
+ (60*dwFrameRateTicks)) // wrong waiting times\r
+ _ticks_since_last_update=dwWaitTime;\r
+\r
+ while(_ticks_since_last_update<dwWaitTime) // -> loop until we have reached the real psx time\r
+ { // (that's the additional limitation, yup)\r
+ if(bIsPerformanceCounter)\r
+ {\r
+ QueryPerformanceCounter(&CurrentTime);\r
+ _ticks_since_last_update = dwT+CurrentTime.LowPart - LastTime.LowPart;\r
+ }\r
+ else\r
+ {\r
+ curticks = timeGetTime();\r
+ _ticks_since_last_update = dwT+curticks - lastticks;\r
+ }\r
+ }\r
+ }\r
+ else // we were still too slow ?!!?\r
+ {\r
+ if(iAdditionalSkip<MAXSKIP) // -> well, somewhen we really have to stop skipping on very slow systems\r
+ {\r
+ iAdditionalSkip++; // -> inc our watchdog var\r
+ dwLaceCnt=0; // -> reset lace count\r
+ if(bIsPerformanceCounter) // -> ok, start time of the next frame\r
+ QueryPerformanceCounter(&LastTime);\r
+ lastticks = timeGetTime();\r
+ return; // -> done, we will skip next frame to get more speed\r
+ } \r
+ }\r
+ }\r
+\r
+ bInitCap=FALSE; // -> ok, we have inited the frameskip func\r
+ iAdditionalSkip=0; // -> init additional skip\r
+ bSkipNextFrame=FALSE; // -> we don't skip the next frame\r
+ if(bIsPerformanceCounter) // -> we store the start time of the next frame\r
+ QueryPerformanceCounter(&LastTime);\r
+ lastticks = timeGetTime();\r
+ dwLaceCnt=0; // -> and we start to count the laces \r
+ dwLastLace=0; \r
+ _ticks_since_last_update=0;\r
+ return; // -> done, the next frame will get drawn\r
+ }\r
+\r
+ bSkipNextFrame=FALSE; // init the frame skip signal to 'no skipping' first\r
+\r
+ if(bIsPerformanceCounter) // get the current time (we are now at the end of one drawn frame)\r
+ {\r
+ QueryPerformanceCounter(&CurrentTime);\r
+ _ticks_since_last_update = CurrentTime.LowPart - LastTime.LowPart;\r
+ }\r
+ else\r
+ {\r
+ curticks = timeGetTime();\r
+ _ticks_since_last_update = curticks - lastticks;\r
+ }\r
+\r
+ dwLastLace=dwLaceCnt; // store curr count (frame limitation helper)\r
+ dwWaitTime=dwLaceCnt*dwFrameRateTicks; // calc the 'real psx lace time'\r
+\r
+ if(_ticks_since_last_update>dwWaitTime) // hey, we needed way too long for that frame...\r
+ {\r
+ if(bUseFrameLimit) // if limitation, we skip just next frame,\r
+ { // and decide after, if we need to do more\r
+ iNumSkips=0;\r
+ }\r
+ else\r
+ {\r
+ iNumSkips=_ticks_since_last_update/dwWaitTime; // -> calc number of frames to skip to catch up\r
+ iNumSkips--; // -> since we already skip next frame, one down\r
+ if(iNumSkips>MAXSKIP) iNumSkips=MAXSKIP; // -> well, somewhere we have to draw a line\r
+ }\r
+ bSkipNextFrame = TRUE; // -> signal for skipping the next frame\r
+ }\r
+ else // we were faster than real psx? fine :)\r
+ if(bUseFrameLimit) // frame limit used? so we wait til the 'real psx time' has been reached\r
+ {\r
+ if(dwLaceCnt>MAXLACE) // -> security check\r
+ _ticks_since_last_update=dwWaitTime;\r
+\r
+ while(_ticks_since_last_update<dwWaitTime) // just do a waiting loop...\r
+ {\r
+ if(bIsPerformanceCounter)\r
+ {\r
+ QueryPerformanceCounter(&CurrentTime);\r
+ _ticks_since_last_update = CurrentTime.LowPart - LastTime.LowPart;\r
+ }\r
+ else\r
+ {\r
+ curticks = timeGetTime();\r
+ _ticks_since_last_update = curticks - lastticks;\r
+ }\r
+ }\r
+ }\r
+\r
+ if(bIsPerformanceCounter) // ok, start time of the next frame\r
+ QueryPerformanceCounter(&LastTime);\r
+ lastticks = timeGetTime();\r
+ }\r
+\r
+ dwLaceCnt=0; // init lace counter\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void calcfps(void)\r
+{\r
+ static DWORD curticks,_ticks_since_last_update,lastticks;\r
+ static long fps_cnt = 0;\r
+ static DWORD fps_tck = 1;\r
+ static LARGE_INTEGER CurrentTime;\r
+ static LARGE_INTEGER LastTime;\r
+ static long fpsskip_cnt = 0;\r
+ static DWORD fpsskip_tck = 1;\r
+\r
+ if(bIsPerformanceCounter)\r
+ {\r
+ QueryPerformanceCounter(&CurrentTime);\r
+ _ticks_since_last_update=CurrentTime.LowPart-LastTime.LowPart;\r
+ \r
+ //--------------------------------------------------//\r
+ curticks = timeGetTime();\r
+ if(_ticks_since_last_update>(liCPUFrequency.LowPart>>1))\r
+ _ticks_since_last_update = (liCPUFrequency.LowPart * (curticks - lastticks))/1000;\r
+ lastticks=curticks;\r
+ //--------------------------------------------------//\r
+\r
+ if(bUseFrameSkip && !bUseFrameLimit && _ticks_since_last_update) \r
+ fps_skip=min(fps_skip,(((float)liCPUFrequency.LowPart) / ((float)_ticks_since_last_update) +1.0f));\r
+\r
+ LastTime.HighPart = CurrentTime.HighPart;\r
+ LastTime.LowPart = CurrentTime.LowPart;\r
+ }\r
+ else\r
+ {\r
+ curticks = timeGetTime();\r
+ _ticks_since_last_update=curticks-lastticks;\r
+\r
+ if(bUseFrameSkip && !bUseFrameLimit && _ticks_since_last_update)\r
+ fps_skip=min(fps_skip,((float)1000/(float)_ticks_since_last_update+1.0f));\r
+\r
+ lastticks = curticks;\r
+ }\r
+\r
+ if(bUseFrameSkip && bUseFrameLimit)\r
+ {\r
+ fpsskip_tck += _ticks_since_last_update;\r
+\r
+ if(++fpsskip_cnt==2)\r
+ {\r
+ if(bIsPerformanceCounter)\r
+ fps_skip = ((float)liCPUFrequency.LowPart) / ((float)fpsskip_tck) *2.0f;\r
+ else\r
+ fps_skip = (float)2000/(float)fpsskip_tck;\r
+\r
+ fps_skip +=6.0f;\r
+\r
+ fpsskip_cnt = 0;\r
+ fpsskip_tck = 1;\r
+ }\r
+ }\r
+\r
+ fps_tck += _ticks_since_last_update;\r
+\r
+ if(++fps_cnt==10)\r
+ {\r
+ if(bIsPerformanceCounter)\r
+ fps_cur = ((float)liCPUFrequency.LowPart) / ((float)fps_tck) *10.0f;\r
+ else\r
+ fps_cur = (float)10000/(float)fps_tck;\r
+\r
+ fps_cnt = 0;\r
+ fps_tck = 1;\r
+\r
+ if(bUseFrameLimit && fps_cur>fFrameRateHz) // optical adjust ;) avoids flickering fps display\r
+ fps_cur=fFrameRateHz;\r
+ }\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// PC FPS skipping / limit\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void PCFrameCap(void)\r
+{\r
+ static DWORD curticks, lastticks, _ticks_since_last_update;\r
+ static DWORD TicksToWait = 0;\r
+ static LARGE_INTEGER CurrentTime;\r
+ static LARGE_INTEGER LastTime;\r
+ BOOL Waiting = TRUE;\r
+\r
+ while (Waiting)\r
+ {\r
+ if(bIsPerformanceCounter)\r
+ {\r
+ QueryPerformanceCounter(&CurrentTime);\r
+ _ticks_since_last_update = CurrentTime.LowPart - LastTime.LowPart;\r
+\r
+ //------------------------------------------------//\r
+ curticks = timeGetTime();\r
+ if(_ticks_since_last_update>(liCPUFrequency.LowPart>>1)) \r
+ {\r
+ if(curticks < lastticks)\r
+ _ticks_since_last_update = TicksToWait+1;\r
+ else _ticks_since_last_update = (liCPUFrequency.LowPart * (curticks - lastticks))/1000;\r
+ }\r
+ //------------------------------------------------//\r
+\r
+ if ((_ticks_since_last_update > TicksToWait) ||\r
+ (CurrentTime.LowPart < LastTime.LowPart))\r
+ {\r
+ Waiting = FALSE;\r
+\r
+ lastticks=curticks; \r
+\r
+ LastTime.HighPart = CurrentTime.HighPart;\r
+ LastTime.LowPart = CurrentTime.LowPart;\r
+ TicksToWait = (liCPUFrequency.LowPart / fFrameRateHz);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ curticks = timeGetTime();\r
+ _ticks_since_last_update = curticks - lastticks;\r
+ if ((_ticks_since_last_update > TicksToWait) || \r
+ (curticks < lastticks))\r
+ {\r
+ Waiting = FALSE;\r
+ lastticks = curticks;\r
+ TicksToWait = (1000 / (DWORD)fFrameRateHz);\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void PCcalcfps(void)\r
+{\r
+ static DWORD curticks,_ticks_since_last_update,lastticks;\r
+ static long fps_cnt = 0;\r
+ static float fps_acc = 0;\r
+ static LARGE_INTEGER CurrentTime;\r
+ static LARGE_INTEGER LastTime;\r
+ float CurrentFPS=0; \r
+ \r
+ if(bIsPerformanceCounter)\r
+ {\r
+ QueryPerformanceCounter(&CurrentTime);\r
+ _ticks_since_last_update=CurrentTime.LowPart-LastTime.LowPart;\r
+\r
+ //--------------------------------------------------//\r
+ curticks = timeGetTime();\r
+ if(_ticks_since_last_update>(liCPUFrequency.LowPart>>1)) \r
+ _ticks_since_last_update = (liCPUFrequency.LowPart * (curticks - lastticks))/1000;\r
+ lastticks=curticks;\r
+ //--------------------------------------------------//\r
+\r
+ if(_ticks_since_last_update)\r
+ {\r
+ CurrentFPS = ((float)liCPUFrequency.LowPart) / ((float)_ticks_since_last_update);\r
+ }\r
+ else CurrentFPS = 0;\r
+ LastTime.HighPart = CurrentTime.HighPart;\r
+ LastTime.LowPart = CurrentTime.LowPart;\r
+ }\r
+ else\r
+ {\r
+ curticks = timeGetTime();\r
+ if(_ticks_since_last_update=curticks-lastticks)\r
+ CurrentFPS=(float)1000/(float)_ticks_since_last_update;\r
+ else CurrentFPS = 0;\r
+ lastticks = curticks;\r
+ }\r
+\r
+ fps_acc += CurrentFPS;\r
+\r
+ if(++fps_cnt==10)\r
+ {\r
+ fps_cur = fps_acc / 10;\r
+ fps_acc = 0;\r
+ fps_cnt = 0;\r
+ }\r
+ \r
+ fps_skip=CurrentFPS+1.0f;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void SetAutoFrameCap(void)\r
+{\r
+ if(iFrameLimit==1)\r
+ {\r
+ fFrameRateHz = fFrameRate;\r
+ if(bIsPerformanceCounter)\r
+ dwFrameRateTicks=(liCPUFrequency.LowPart / fFrameRateHz);\r
+ else dwFrameRateTicks=(1000 / (DWORD)fFrameRateHz);\r
+ return;\r
+ }\r
+\r
+ if(dwActFixes&128)\r
+ {\r
+ if (PSXDisplay.Interlaced)\r
+ fFrameRateHz = PSXDisplay.PAL?50.0f:60.0f;\r
+ else fFrameRateHz = PSXDisplay.PAL?25.0f:30.0f;\r
+ }\r
+ else\r
+ {\r
+ //fFrameRateHz = PSXDisplay.PAL?50.0f:59.94f;\r
+\r
+ if(PSXDisplay.PAL)\r
+ {\r
+ if (STATUSREG&GPUSTATUS_INTERLACED)\r
+ fFrameRateHz=33868800.0f/677343.75f; // 50.00238\r
+ else fFrameRateHz=33868800.0f/680595.00f; // 49.76351\r
+ } \r
+ else\r
+ {\r
+ if (STATUSREG&GPUSTATUS_INTERLACED)\r
+ fFrameRateHz=33868800.0f/565031.25f; // 59.94146\r
+ else fFrameRateHz=33868800.0f/566107.50f; // 59.82750\r
+ }\r
+\r
+ if(bIsPerformanceCounter)\r
+ dwFrameRateTicks=(liCPUFrequency.LowPart / fFrameRateHz);\r
+ else dwFrameRateTicks=(1000 / (DWORD)fFrameRateHz);\r
+ }\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void InitFrameCap(void) // inits cpu frequency info (on gpu startup)\r
+{\r
+ if (QueryPerformanceFrequency (&liCPUFrequency))\r
+ bIsPerformanceCounter = TRUE;\r
+ else bIsPerformanceCounter = FALSE;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void ReInitFrameCap(void)\r
+{\r
+ BOOL bOldPerformanceCounter=bIsPerformanceCounter; // store curr timer mode\r
+\r
+ if(dwActFixes&0x10000) // check game fix... high performance counters are bad on some mb chipsets\r
+ bIsPerformanceCounter=FALSE;\r
+ else \r
+ {\r
+ if (QueryPerformanceFrequency (&liCPUFrequency))\r
+ bIsPerformanceCounter = TRUE;\r
+ else bIsPerformanceCounter = FALSE;\r
+ }\r
+ \r
+ if(bOldPerformanceCounter!=bIsPerformanceCounter) // changed?\r
+ {\r
+ bInitCap = TRUE;\r
+ SetAutoFrameCap();\r
+ }\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void SetFrameRateConfig(void)\r
+{\r
+ if(fFrameRateHz==0) \r
+ {\r
+ if(iFrameLimit==2) fFrameRateHz=59.94f; // auto framerate? set some init val (no pal/ntsc known yet)\r
+ else fFrameRateHz=fFrameRate; // else set user framerate\r
+ }\r
+\r
+ if(bIsPerformanceCounter)\r
+ dwFrameRateTicks=(liCPUFrequency.LowPart / fFrameRateHz);\r
+ else dwFrameRateTicks=(1000 / (DWORD)fFrameRateHz);\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+// LINUX ---------------------------------------------\r
+\r
+#else\r
+\r
+#define TIMEBASE 100000\r
+\r
+// hehehe... using same func name as with win32 ;) wow, are we genius ;)\r
+unsigned long timeGetTime()\r
+{\r
+ struct timeval tv;\r
+ gettimeofday(&tv, 0); // well, maybe there are better ways\r
+ return tv.tv_sec * 100000 + tv.tv_usec/10; // to do that in linux, but at least it works\r
+}\r
+\r
+void FrameCap(void)\r
+{\r
+ static unsigned long curticks, lastticks, _ticks_since_last_update;\r
+ static unsigned long TicksToWait = 0;\r
+ bool Waiting = TRUE;\r
+\r
+ {\r
+ curticks = timeGetTime();\r
+ _ticks_since_last_update = curticks - lastticks;\r
+\r
+ if((_ticks_since_last_update > TicksToWait) ||\r
+ (curticks <lastticks))\r
+ {\r
+ lastticks = curticks;\r
+\r
+ if((_ticks_since_last_update-TicksToWait) > dwFrameRateTicks)\r
+ TicksToWait=0;\r
+ else TicksToWait=dwFrameRateTicks-(_ticks_since_last_update-TicksToWait);\r
+ }\r
+ else\r
+ {\r
+ while (Waiting) \r
+ {\r
+ curticks = timeGetTime(); \r
+ _ticks_since_last_update = curticks - lastticks; \r
+ if ((_ticks_since_last_update > TicksToWait) ||\r
+ (curticks < lastticks)) \r
+ { \r
+ Waiting = FALSE;\r
+ lastticks = curticks;\r
+ TicksToWait = dwFrameRateTicks; \r
+ } \r
+ } \r
+ } \r
+ } \r
+} \r
+ \r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#define MAXSKIP 120\r
+#define MAXLACE 16\r
+\r
+void FrameSkip(void)\r
+{\r
+ static int iNumSkips=0,iAdditionalSkip=0; // number of additional frames to skip\r
+ static DWORD dwLastLace=0; // helper var for frame limitation\r
+ static DWORD curticks, lastticks, _ticks_since_last_update;\r
+\r
+ if(!dwLaceCnt) return; // important: if no updatelace happened, we ignore it completely\r
+\r
+ if(iNumSkips) // we are in skipping mode?\r
+ {\r
+ dwLastLace+=dwLaceCnt; // -> calc frame limit helper (number of laces)\r
+ bSkipNextFrame = TRUE; // -> we skip next frame\r
+ iNumSkips--; // -> ok, one done\r
+ }\r
+ else // ok, no additional skipping has to be done... \r
+ { // we check now, if some limitation is needed, or a new skipping has to get started\r
+ DWORD dwWaitTime;\r
+\r
+ if(bInitCap || bSkipNextFrame) // first time or we skipped before?\r
+ {\r
+ if(bUseFrameLimit && !bInitCap) // frame limit wanted and not first time called?\r
+ {\r
+ DWORD dwT=_ticks_since_last_update; // -> that's the time of the last drawn frame\r
+ dwLastLace+=dwLaceCnt; // -> and that's the number of updatelace since the start of the last drawn frame\r
+\r
+ curticks = timeGetTime();\r
+ _ticks_since_last_update= dwT+curticks - lastticks;\r
+\r
+ dwWaitTime=dwLastLace*dwFrameRateTicks; // -> and now we calc the time the real psx would have needed\r
+\r
+ if(_ticks_since_last_update<dwWaitTime) // -> we were too fast?\r
+ { \r
+ if((dwWaitTime-_ticks_since_last_update)> // -> some more security, to prevent\r
+ (60*dwFrameRateTicks)) // wrong waiting times\r
+ _ticks_since_last_update=dwWaitTime;\r
+\r
+ while(_ticks_since_last_update<dwWaitTime) // -> loop until we have reached the real psx time\r
+ { // (that's the additional limitation, yup)\r
+ curticks = timeGetTime();\r
+ _ticks_since_last_update = dwT+curticks - lastticks;\r
+ }\r
+ }\r
+ else // we were still too slow ?!!?\r
+ {\r
+ if(iAdditionalSkip<MAXSKIP) // -> well, somewhen we really have to stop skipping on very slow systems\r
+ {\r
+ iAdditionalSkip++; // -> inc our watchdog var\r
+ dwLaceCnt=0; // -> reset lace count\r
+ lastticks = timeGetTime();\r
+ return; // -> done, we will skip next frame to get more speed\r
+ }\r
+ }\r
+ }\r
+\r
+ bInitCap=FALSE; // -> ok, we have inited the frameskip func\r
+ iAdditionalSkip=0; // -> init additional skip\r
+ bSkipNextFrame=FALSE; // -> we don't skip the next frame\r
+ lastticks = timeGetTime();\r
+ dwLaceCnt=0; // -> and we start to count the laces \r
+ dwLastLace=0; \r
+ _ticks_since_last_update=0;\r
+ return; // -> done, the next frame will get drawn\r
+ }\r
+\r
+ bSkipNextFrame=FALSE; // init the frame skip signal to 'no skipping' first\r
+\r
+ curticks = timeGetTime();\r
+ _ticks_since_last_update = curticks - lastticks;\r
+\r
+ dwLastLace=dwLaceCnt; // store curr count (frame limitation helper)\r
+ dwWaitTime=dwLaceCnt*dwFrameRateTicks; // calc the 'real psx lace time'\r
+\r
+ if(_ticks_since_last_update>dwWaitTime) // hey, we needed way too long for that frame...\r
+ {\r
+ if(bUseFrameLimit) // if limitation, we skip just next frame,\r
+ { // and decide after, if we need to do more\r
+ iNumSkips=0;\r
+ }\r
+ else\r
+ {\r
+ iNumSkips=_ticks_since_last_update/dwWaitTime; // -> calc number of frames to skip to catch up\r
+ iNumSkips--; // -> since we already skip next frame, one down\r
+ if(iNumSkips>MAXSKIP) iNumSkips=MAXSKIP; // -> well, somewhere we have to draw a line\r
+ }\r
+ bSkipNextFrame = TRUE; // -> signal for skipping the next frame\r
+ }\r
+ else // we were faster than real psx? fine :)\r
+ if(bUseFrameLimit) // frame limit used? so we wait til the 'real psx time' has been reached\r
+ {\r
+ if(dwLaceCnt>MAXLACE) // -> security check\r
+ _ticks_since_last_update=dwWaitTime;\r
+\r
+ while(_ticks_since_last_update<dwWaitTime) // just do a waiting loop...\r
+ {\r
+ curticks = timeGetTime();\r
+ _ticks_since_last_update = curticks - lastticks;\r
+ }\r
+ }\r
+\r
+ lastticks = timeGetTime();\r
+ }\r
+\r
+ dwLaceCnt=0; // init lace counter\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////// \r
+ \r
+void calcfps(void) \r
+{ \r
+ static unsigned long curticks,_ticks_since_last_update,lastticks; \r
+ static long fps_cnt = 0;\r
+ static unsigned long fps_tck = 1; \r
+ static long fpsskip_cnt = 0;\r
+ static unsigned long fpsskip_tck = 1;\r
+ \r
+ { \r
+ curticks = timeGetTime(); \r
+ _ticks_since_last_update=curticks-lastticks; \r
+ \r
+ if(bUseFrameSkip && !bUseFrameLimit && _ticks_since_last_update) \r
+ fps_skip=min(fps_skip,((float)TIMEBASE/(float)_ticks_since_last_update+1.0f));\r
+ \r
+ lastticks = curticks; \r
+ } \r
+ \r
+ if(bUseFrameSkip && bUseFrameLimit)\r
+ {\r
+ fpsskip_tck += _ticks_since_last_update;\r
+\r
+ if(++fpsskip_cnt==2)\r
+ {\r
+ fps_skip = (float)2000/(float)fpsskip_tck;\r
+\r
+ fps_skip +=6.0f;\r
+\r
+ fpsskip_cnt = 0;\r
+ fpsskip_tck = 1;\r
+ }\r
+ }\r
+\r
+ fps_tck += _ticks_since_last_update; \r
+ \r
+ if(++fps_cnt==10) \r
+ { \r
+ fps_cur = (float)(TIMEBASE*10)/(float)fps_tck; \r
+\r
+ fps_cnt = 0; \r
+ fps_tck = 1; \r
+ \r
+ if(bUseFrameLimit && fps_cur>fFrameRateHz) // optical adjust ;) avoids flickering fps display \r
+ fps_cur=fFrameRateHz; \r
+ } \r
+} \r
+\r
+void PCFrameCap (void) \r
+{\r
+ static unsigned long curticks, lastticks, _ticks_since_last_update;\r
+ static unsigned long TicksToWait = 0;\r
+ bool Waiting = TRUE; \r
+ \r
+ while (Waiting) \r
+ {\r
+ curticks = timeGetTime(); \r
+ _ticks_since_last_update = curticks - lastticks; \r
+ if ((_ticks_since_last_update > TicksToWait) || \r
+ (curticks < lastticks)) \r
+ { \r
+ Waiting = FALSE; \r
+ lastticks = curticks; \r
+ TicksToWait = (TIMEBASE / (unsigned long)fFrameRateHz); \r
+ } \r
+ } \r
+} \r
+ \r
+//////////////////////////////////////////////////////////////////////// \r
+ \r
+void PCcalcfps(void) \r
+{ \r
+ static unsigned long curticks,_ticks_since_last_update,lastticks; \r
+ static long fps_cnt = 0; \r
+ static float fps_acc = 0;\r
+ float CurrentFPS=0; \r
+ \r
+ curticks = timeGetTime(); \r
+ _ticks_since_last_update=curticks-lastticks;\r
+ if(_ticks_since_last_update) \r
+ CurrentFPS=(float)TIMEBASE/(float)_ticks_since_last_update;\r
+ else CurrentFPS = 0;\r
+ lastticks = curticks; \r
+ \r
+ fps_acc += CurrentFPS;\r
+\r
+ if(++fps_cnt==10)\r
+ {\r
+ fps_cur = fps_acc / 10;\r
+ fps_acc = 0;\r
+ fps_cnt = 0;\r
+ }\r
+\r
+ fps_skip=CurrentFPS+1.0f;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void SetAutoFrameCap(void)\r
+{\r
+ if(iFrameLimit==1)\r
+ {\r
+ fFrameRateHz = fFrameRate;\r
+ dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz);\r
+ return;\r
+ }\r
+\r
+ if(dwActFixes&128)\r
+ {\r
+ if (PSXDisplay.Interlaced)\r
+ fFrameRateHz = PSXDisplay.PAL?50.0f:60.0f;\r
+ else fFrameRateHz = PSXDisplay.PAL?25.0f:30.0f;\r
+ }\r
+ else\r
+ {\r
+ //fFrameRateHz = PSXDisplay.PAL?50.0f:59.94f;\r
+\r
+ if(PSXDisplay.PAL)\r
+ {\r
+ if (STATUSREG&GPUSTATUS_INTERLACED)\r
+ fFrameRateHz=33868800.0f/677343.75f; // 50.00238\r
+ else fFrameRateHz=33868800.0f/680595.00f; // 49.76351\r
+ } \r
+ else\r
+ {\r
+ if (STATUSREG&GPUSTATUS_INTERLACED)\r
+ fFrameRateHz=33868800.0f/565031.25f; // 59.94146\r
+ else fFrameRateHz=33868800.0f/566107.50f; // 59.82750\r
+ }\r
+\r
+ dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz);\r
+ }\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void SetFrameRateConfig(void)\r
+{\r
+ if(!fFrameRate) fFrameRate=200.0f;\r
+\r
+ if(fFrameRateHz==0) \r
+ { \r
+ if(iFrameLimit==2) fFrameRateHz=59.94f; // auto framerate? set some init val (no pal/ntsc known yet)\r
+ else fFrameRateHz=fFrameRate; // else set user framerate\r
+ }\r
+\r
+ dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz);\r
+\r
+ if(iFrameLimit==2) SetAutoFrameCap();\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void InitFrameCap(void)\r
+{\r
+ // nothing on linux\r
+}\r
+\r
+void ReInitFrameCap(void)\r
+{\r
+ // nothing on linux\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#endif\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void CheckFrameRate(void) // called in updatelace (on every emulated psx vsync)\r
+{\r
+ if(bUseFrameSkip) \r
+ {\r
+ if(!(dwActFixes&0x100))\r
+ {\r
+ dwLaceCnt++; // -> and store cnt of vsync between frames\r
+ if(dwLaceCnt>=MAXLACE && bUseFrameLimit) \r
+ {\r
+ if(dwLaceCnt==MAXLACE) bInitCap=TRUE;\r
+ FrameCap();\r
+ }\r
+ }\r
+ else if(bUseFrameLimit) FrameCap();\r
+ calcfps(); // -> calc fps display in skipping mode\r
+ } \r
+ else // -> non-skipping mode:\r
+ {\r
+ if(bUseFrameLimit) FrameCap();\r
+ calcfps(); \r
+ }\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void CALLBACK GPUsetframelimit(unsigned long option) // new EPSXE interface func: main emu can enable/disable fps limitation this way\r
+{\r
+ bInitCap = TRUE;\r
+\r
+ if(option==1) // emu says: limit\r
+ {\r
+ bUseFrameLimit=TRUE;bUseFrameSkip=FALSE;iFrameLimit=2;\r
+ SetAutoFrameCap();\r
+ }\r
+ else // emu says: no limit\r
+ {\r
+ bUseFrameLimit=FALSE;\r
+ }\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r