1 /***************************************************************************
\r
4 begin : Sun Mar 08 2009
\r
5 copyright : (C) 1999-2009 by Pete Bernert
\r
6 web : www.pbernert.com
\r
7 ***************************************************************************/
\r
9 /***************************************************************************
\r
11 * This program is free software; you can redistribute it and/or modify *
\r
12 * it under the terms of the GNU General Public License as published by *
\r
13 * the Free Software Foundation; either version 2 of the License, or *
\r
14 * (at your option) any later version. See also the license.txt file for *
\r
15 * additional informations. *
\r
17 ***************************************************************************/
\r
19 //*************************************************************************//
\r
20 // History of changes:
\r
22 // 2009/03/08 - Pete
\r
23 // - generic cleanup for the Peops release
\r
25 //*************************************************************************//
\r
31 #include "externals.h"
\r
33 ////////////////////////////////////////////////////////////////////////
\r
35 ////////////////////////////////////////////////////////////////////////
\r
37 BOOL bIsPerformanceCounter=FALSE;
\r
38 float fFrameRateHz=0;
\r
39 DWORD dwFrameRateTicks=16;
\r
42 BOOL bUseFrameLimit=FALSE;
\r
43 BOOL bUseFrameSkip=0;
\r
46 ////////////////////////////////////////////////////////////////////////
\r
47 // FPS skipping / limit
\r
48 ////////////////////////////////////////////////////////////////////////
\r
50 BOOL bInitCap = TRUE;
\r
54 #define TIMEBASE 100000
\r
56 unsigned long timeGetTime()
\r
59 gettimeofday(&tv, 0); // well, maybe there are better ways
\r
60 return tv.tv_sec * 100000 + tv.tv_usec/10; // to do that in linux, but at least it works
\r
65 static unsigned long curticks, lastticks, _ticks_since_last_update;
\r
66 static unsigned long TicksToWait = 0;
\r
67 bool Waiting = TRUE;
\r
70 curticks = timeGetTime();
\r
71 _ticks_since_last_update = curticks - lastticks;
\r
73 if((_ticks_since_last_update > TicksToWait) ||
\r
74 (curticks <lastticks))
\r
76 lastticks = curticks;
\r
78 if((_ticks_since_last_update-TicksToWait) > dwFrameRateTicks)
\r
80 else TicksToWait=dwFrameRateTicks-(_ticks_since_last_update-TicksToWait);
\r
86 curticks = timeGetTime();
\r
87 _ticks_since_last_update = curticks - lastticks;
\r
88 if ((_ticks_since_last_update > TicksToWait) ||
\r
89 (curticks < lastticks))
\r
92 lastticks = curticks;
\r
93 TicksToWait = dwFrameRateTicks;
\r
100 #define MAXSKIP 120
\r
103 void FrameSkip(void)
\r
105 static int iNumSkips=0,iAdditionalSkip=0; // number of additional frames to skip
\r
106 static DWORD dwLastLace=0; // helper var for frame limitation
\r
107 static DWORD curticks, lastticks, _ticks_since_last_update;
\r
109 if(!dwLaceCnt) return; // important: if no updatelace happened, we ignore it completely
\r
111 if(iNumSkips) // we are in skipping mode?
\r
113 dwLastLace+=dwLaceCnt; // -> calc frame limit helper (number of laces)
\r
114 bSkipNextFrame = TRUE; // -> we skip next frame
\r
115 iNumSkips--; // -> ok, one done
\r
117 else // ok, no additional skipping has to be done...
\r
118 { // we check now, if some limitation is needed, or a new skipping has to get started
\r
121 if(bInitCap || bSkipNextFrame) // first time or we skipped before?
\r
123 if(bUseFrameLimit && !bInitCap) // frame limit wanted and not first time called?
\r
125 DWORD dwT=_ticks_since_last_update; // -> that's the time of the last drawn frame
\r
126 dwLastLace+=dwLaceCnt; // -> and that's the number of updatelace since the start of the last drawn frame
\r
128 curticks = timeGetTime();
\r
129 _ticks_since_last_update= dwT+curticks - lastticks;
\r
131 dwWaitTime=dwLastLace*dwFrameRateTicks; // -> and now we calc the time the real psx would have needed
\r
133 if(_ticks_since_last_update<dwWaitTime) // -> we were too fast?
\r
135 if((dwWaitTime-_ticks_since_last_update)> // -> some more security, to prevent
\r
136 (60*dwFrameRateTicks)) // wrong waiting times
\r
137 _ticks_since_last_update=dwWaitTime;
\r
139 while(_ticks_since_last_update<dwWaitTime) // -> loop until we have reached the real psx time
\r
140 { // (that's the additional limitation, yup)
\r
141 curticks = timeGetTime();
\r
142 _ticks_since_last_update = dwT+curticks - lastticks;
\r
145 else // we were still too slow ?!!?
\r
147 if(iAdditionalSkip<MAXSKIP) // -> well, somewhen we really have to stop skipping on very slow systems
\r
149 iAdditionalSkip++; // -> inc our watchdog var
\r
150 dwLaceCnt=0; // -> reset lace count
\r
151 lastticks = timeGetTime();
\r
152 return; // -> done, we will skip next frame to get more speed
\r
157 bInitCap=FALSE; // -> ok, we have inited the frameskip func
\r
158 iAdditionalSkip=0; // -> init additional skip
\r
159 bSkipNextFrame=FALSE; // -> we don't skip the next frame
\r
160 lastticks = timeGetTime();
\r
161 dwLaceCnt=0; // -> and we start to count the laces
\r
163 _ticks_since_last_update=0;
\r
164 return; // -> done, the next frame will get drawn
\r
167 bSkipNextFrame=FALSE; // init the frame skip signal to 'no skipping' first
\r
169 curticks = timeGetTime();
\r
170 _ticks_since_last_update = curticks - lastticks;
\r
172 dwLastLace=dwLaceCnt; // store curr count (frame limitation helper)
\r
173 dwWaitTime=dwLaceCnt*dwFrameRateTicks; // calc the 'real psx lace time'
\r
175 if(_ticks_since_last_update>dwWaitTime) // hey, we needed way too long for that frame...
\r
177 if(bUseFrameLimit) // if limitation, we skip just next frame,
\r
178 { // and decide after, if we need to do more
\r
183 iNumSkips=_ticks_since_last_update/dwWaitTime; // -> calc number of frames to skip to catch up
\r
184 iNumSkips--; // -> since we already skip next frame, one down
\r
185 if(iNumSkips>MAXSKIP) iNumSkips=MAXSKIP; // -> well, somewhere we have to draw a line
\r
187 bSkipNextFrame = TRUE; // -> signal for skipping the next frame
\r
189 else // we were faster than real psx? fine :)
\r
190 if(bUseFrameLimit) // frame limit used? so we wait til the 'real psx time' has been reached
\r
192 if(dwLaceCnt>MAXLACE) // -> security check
\r
193 _ticks_since_last_update=dwWaitTime;
\r
195 while(_ticks_since_last_update<dwWaitTime) // just do a waiting loop...
\r
197 curticks = timeGetTime();
\r
198 _ticks_since_last_update = curticks - lastticks;
\r
202 lastticks = timeGetTime();
\r
205 dwLaceCnt=0; // init lace counter
\r
208 void calcfps(void)
\r
210 static unsigned long curticks,_ticks_since_last_update,lastticks;
\r
211 static long fps_cnt = 0;
\r
212 static unsigned long fps_tck = 1;
\r
213 static long fpsskip_cnt = 0;
\r
214 static unsigned long fpsskip_tck = 1;
\r
217 curticks = timeGetTime();
\r
218 _ticks_since_last_update=curticks-lastticks;
\r
220 if(bUseFrameSkip && !bUseFrameLimit && _ticks_since_last_update)
\r
221 fps_skip=min(fps_skip,((float)TIMEBASE/(float)_ticks_since_last_update+1.0f));
\r
223 lastticks = curticks;
\r
226 if(bUseFrameSkip && bUseFrameLimit)
\r
228 fpsskip_tck += _ticks_since_last_update;
\r
230 if(++fpsskip_cnt==2)
\r
232 fps_skip = (float)2000/(float)fpsskip_tck;
\r
241 fps_tck += _ticks_since_last_update;
\r
245 fps_cur = (float)(TIMEBASE*10)/(float)fps_tck;
\r
250 if(bUseFrameLimit && fps_cur>fFrameRateHz) // optical adjust ;) avoids flickering fps display
\r
251 fps_cur=fFrameRateHz;
\r
255 void PCFrameCap (void)
\r
257 static unsigned long curticks, lastticks, _ticks_since_last_update;
\r
258 static unsigned long TicksToWait = 0;
\r
259 bool Waiting = TRUE;
\r
263 curticks = timeGetTime();
\r
264 _ticks_since_last_update = curticks - lastticks;
\r
265 if ((_ticks_since_last_update > TicksToWait) ||
\r
266 (curticks < lastticks))
\r
269 lastticks = curticks;
\r
270 TicksToWait = (TIMEBASE / (unsigned long)fFrameRateHz);
\r
275 void PCcalcfps(void)
\r
277 static unsigned long curticks,_ticks_since_last_update,lastticks;
\r
278 static long fps_cnt = 0;
\r
279 static float fps_acc = 0;
\r
280 float CurrentFPS=0;
\r
282 curticks = timeGetTime();
\r
283 _ticks_since_last_update=curticks-lastticks;
\r
284 if(_ticks_since_last_update)
\r
285 CurrentFPS=(float)TIMEBASE/(float)_ticks_since_last_update;
\r
286 else CurrentFPS = 0;
\r
287 lastticks = curticks;
\r
289 fps_acc += CurrentFPS;
\r
293 fps_cur = fps_acc / 10;
\r
298 fps_skip=CurrentFPS+1.0f;
\r
301 void SetAutoFrameCap(void)
\r
305 fFrameRateHz = fFrameRate;
\r
306 dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz);
\r
312 if (PSXDisplay.Interlaced)
\r
313 fFrameRateHz = PSXDisplay.PAL?50.0f:60.0f;
\r
314 else fFrameRateHz = PSXDisplay.PAL?25.0f:30.0f;
\r
318 //fFrameRateHz = PSXDisplay.PAL?50.0f:59.94f;
\r
322 if (STATUSREG&GPUSTATUS_INTERLACED)
\r
323 fFrameRateHz=33868800.0f/677343.75f; // 50.00238
\r
324 else fFrameRateHz=33868800.0f/680595.00f; // 49.76351
\r
328 if (STATUSREG&GPUSTATUS_INTERLACED)
\r
329 fFrameRateHz=33868800.0f/565031.25f; // 59.94146
\r
330 else fFrameRateHz=33868800.0f/566107.50f; // 59.82750
\r
333 dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz);
\r
337 void SetFrameRateConfig(void)
\r
339 if(!fFrameRate) fFrameRate=200.0f;
\r
341 if(fFrameRateHz==0)
\r
343 if(iFrameLimit==2) fFrameRateHz=59.94f; // auto framerate? set some init val (no pal/ntsc known yet)
\r
344 else fFrameRateHz=fFrameRate; // else set user framerate
\r
347 dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz);
\r
349 if(iFrameLimit==2) SetAutoFrameCap();
\r
352 void InitFrameCap(void)
\r
356 void ReInitFrameCap(void)
\r
360 void CheckFrameRate(void) // called in updatelace (on every emulated psx vsync)
\r
364 if(!(dwActFixes&0x100))
\r
366 dwLaceCnt++; // -> and store cnt of vsync between frames
\r
367 if(dwLaceCnt>=MAXLACE && bUseFrameLimit)
\r
369 if(dwLaceCnt==MAXLACE) bInitCap=TRUE;
\r
373 else if(bUseFrameLimit) FrameCap();
\r
374 calcfps(); // -> calc fps display in skipping mode
\r
376 else // -> non-skipping mode:
\r
378 if(bUseFrameLimit) FrameCap();
\r
379 if(ulKeybits&KEY_SHOWFPS) calcfps();
\r
383 void CALLBACK GPUsetframelimit(unsigned long option) // new EPSXE interface func: main emu can enable/disable fps limitation this way
\r
387 if(option==1) // emu says: limit
\r
389 bUseFrameLimit=TRUE;bUseFrameSkip=FALSE;iFrameLimit=2;
\r
392 else // emu says: no limit
\r
394 bUseFrameLimit=FALSE;
\r