dc89600fc4de3d654e5a32642af94efc58364157
[pcsx_rearmed.git] / plugins / peopsxgl / fps.c
1 /***************************************************************************\r
2                           fps.c  -  description\r
3                              -------------------\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
8 \r
9 /***************************************************************************\r
10  *                                                                         *\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
16  *                                                                         *\r
17  ***************************************************************************/\r
18 \r
19 //*************************************************************************// \r
20 // History of changes:\r
21 //\r
22 // 2009/03/08 - Pete  \r
23 // - generic cleanup for the Peops release\r
24 //\r
25 //*************************************************************************// \r
26 \r
27 #include "stdafx.h"\r
28 \r
29 #define _IN_FPS\r
30 \r
31 #include "externals.h"\r
32 \r
33 ////////////////////////////////////////////////////////////////////////\r
34 // FPS stuff\r
35 ////////////////////////////////////////////////////////////////////////\r
36 \r
37 BOOL           bIsPerformanceCounter=FALSE;\r
38 float          fFrameRateHz=0;\r
39 DWORD          dwFrameRateTicks=16;\r
40 float          fFrameRate;\r
41 int            iFrameLimit;\r
42 BOOL           bUseFrameLimit=FALSE;\r
43 BOOL           bUseFrameSkip=0;\r
44 DWORD          dwLaceCnt=0;\r
45 \r
46 ////////////////////////////////////////////////////////////////////////\r
47 // FPS skipping / limit\r
48 ////////////////////////////////////////////////////////////////////////\r
49 \r
50 BOOL         bInitCap = TRUE; \r
51 float        fps_skip = 0;\r
52 float        fps_cur  = 0;\r
53 \r
54 #define TIMEBASE 100000\r
55 \r
56 unsigned long timeGetTime()\r
57 {\r
58  struct timeval tv;\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
61 }\r
62 \r
63 void FrameCap(void)\r
64 {\r
65  static unsigned long curticks, lastticks, _ticks_since_last_update;\r
66  static unsigned long TicksToWait = 0;\r
67  bool Waiting = TRUE;\r
68 \r
69   {\r
70    curticks = timeGetTime();\r
71    _ticks_since_last_update = curticks - lastticks;\r
72 \r
73     if((_ticks_since_last_update > TicksToWait) ||\r
74        (curticks <lastticks))\r
75     {\r
76      lastticks = curticks;\r
77 \r
78      if((_ticks_since_last_update-TicksToWait) > dwFrameRateTicks)\r
79           TicksToWait=0;\r
80      else TicksToWait=dwFrameRateTicks-(_ticks_since_last_update-TicksToWait);\r
81     }\r
82    else\r
83     {\r
84      while (Waiting) \r
85       {\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
90         { \r
91          Waiting = FALSE;\r
92          lastticks = curticks;\r
93          TicksToWait = dwFrameRateTicks; \r
94         } \r
95       } \r
96     } \r
97   } \r
98\r
99 \r
100 #define MAXSKIP 120\r
101 #define MAXLACE 16\r
102 \r
103 void FrameSkip(void)\r
104 {\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
108 \r
109  if(!dwLaceCnt) return;                                // important: if no updatelace happened, we ignore it completely\r
110 \r
111  if(iNumSkips)                                         // we are in skipping mode?\r
112   {\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
116   }\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
119    DWORD dwWaitTime;\r
120 \r
121    if(bInitCap || bSkipNextFrame)                      // first time or we skipped before?\r
122     {\r
123      if(bUseFrameLimit && !bInitCap)                   // frame limit wanted and not first time called?\r
124       {\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
127 \r
128        curticks = timeGetTime();\r
129        _ticks_since_last_update= dwT+curticks - lastticks;\r
130 \r
131        dwWaitTime=dwLastLace*dwFrameRateTicks;         // -> and now we calc the time the real psx would have needed\r
132 \r
133        if(_ticks_since_last_update<dwWaitTime)         // -> we were too fast?\r
134         {                                    \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
138 \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
143           }\r
144         }\r
145        else                                            // we were still too slow ?!!?\r
146         {\r
147          if(iAdditionalSkip<MAXSKIP)                   // -> well, somewhen we really have to stop skipping on very slow systems\r
148           {\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
153           }\r
154         }\r
155       }\r
156 \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
162      dwLastLace=0;      \r
163      _ticks_since_last_update=0;\r
164      return;                                           // -> done, the next frame will get drawn\r
165     }\r
166 \r
167    bSkipNextFrame=FALSE;                               // init the frame skip signal to 'no skipping' first\r
168 \r
169    curticks = timeGetTime();\r
170    _ticks_since_last_update = curticks - lastticks;\r
171 \r
172    dwLastLace=dwLaceCnt;                               // store curr count (frame limitation helper)\r
173    dwWaitTime=dwLaceCnt*dwFrameRateTicks;              // calc the 'real psx lace time'\r
174 \r
175    if(_ticks_since_last_update>dwWaitTime)             // hey, we needed way too long for that frame...\r
176     {\r
177      if(bUseFrameLimit)                                // if limitation, we skip just next frame,\r
178       {                                                // and decide after, if we need to do more\r
179        iNumSkips=0;\r
180       }\r
181      else\r
182       {\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
186       }\r
187      bSkipNextFrame = TRUE;                            // -> signal for skipping the next frame\r
188     }\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
191     {\r
192      if(dwLaceCnt>MAXLACE)                             // -> security check\r
193       _ticks_since_last_update=dwWaitTime;\r
194 \r
195      while(_ticks_since_last_update<dwWaitTime)        // just do a waiting loop...\r
196       {\r
197        curticks = timeGetTime();\r
198        _ticks_since_last_update = curticks - lastticks;\r
199       }\r
200     }\r
201 \r
202    lastticks = timeGetTime();\r
203   }\r
204 \r
205  dwLaceCnt=0;                                          // init lace counter\r
206 }\r
207 \r
208 void calcfps(void) \r
209\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
215  \r
216   { \r
217    curticks = timeGetTime(); \r
218    _ticks_since_last_update=curticks-lastticks; \r
219  \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
222  \r
223    lastticks = curticks; \r
224   } \r
225  \r
226  if(bUseFrameSkip && bUseFrameLimit)\r
227   {\r
228    fpsskip_tck += _ticks_since_last_update;\r
229 \r
230    if(++fpsskip_cnt==2)\r
231     {\r
232      fps_skip = (float)2000/(float)fpsskip_tck;\r
233 \r
234      fps_skip +=6.0f;\r
235 \r
236      fpsskip_cnt = 0;\r
237      fpsskip_tck = 1;\r
238     }\r
239   }\r
240 \r
241  fps_tck += _ticks_since_last_update; \r
242  \r
243  if(++fps_cnt==10) \r
244   { \r
245    fps_cur = (float)(TIMEBASE*10)/(float)fps_tck; \r
246 \r
247    fps_cnt = 0; \r
248    fps_tck = 1; \r
249  \r
250    if(bUseFrameLimit && fps_cur>fFrameRateHz)            // optical adjust ;) avoids flickering fps display \r
251     fps_cur=fFrameRateHz; \r
252   } \r
253\r
254 \r
255 void PCFrameCap (void) \r
256 {\r
257  static unsigned long curticks, lastticks, _ticks_since_last_update;\r
258  static unsigned long TicksToWait = 0;\r
259  bool Waiting = TRUE; \r
260  \r
261  while (Waiting) \r
262   {\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
267     { \r
268      Waiting = FALSE; \r
269      lastticks = curticks; \r
270      TicksToWait = (TIMEBASE / (unsigned long)fFrameRateHz); \r
271     } \r
272   } \r
273\r
274 \r
275 void PCcalcfps(void) \r
276\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
281   \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
288  \r
289  fps_acc += CurrentFPS;\r
290 \r
291  if(++fps_cnt==10)\r
292   {\r
293    fps_cur = fps_acc / 10;\r
294    fps_acc = 0;\r
295    fps_cnt = 0;\r
296   }\r
297 \r
298  fps_skip=CurrentFPS+1.0f;\r
299 }\r
300 \r
301 void SetAutoFrameCap(void)\r
302 {\r
303  if(iFrameLimit==1)\r
304   {\r
305    fFrameRateHz = fFrameRate;\r
306    dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz);\r
307    return;\r
308   }\r
309 \r
310  if(dwActFixes&128)\r
311   {\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
315   }\r
316  else\r
317   {\r
318    //fFrameRateHz = PSXDisplay.PAL?50.0f:59.94f;\r
319 \r
320    if(PSXDisplay.PAL)\r
321     {\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
325     }                                                     \r
326    else\r
327     {\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
331     }\r
332 \r
333    dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz);\r
334   }\r
335 }\r
336 \r
337 void SetFrameRateConfig(void)\r
338 {\r
339  if(!fFrameRate) fFrameRate=200.0f;\r
340 \r
341  if(fFrameRateHz==0) \r
342   {                                                    \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
345   }\r
346 \r
347  dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz);\r
348 \r
349  if(iFrameLimit==2) SetAutoFrameCap();\r
350 }\r
351 \r
352 void InitFrameCap(void)\r
353 {\r
354 }\r
355 \r
356 void ReInitFrameCap(void)\r
357 {\r
358 }\r
359 \r
360 void CheckFrameRate(void)                              // called in updatelace (on every emulated psx vsync)\r
361 {\r
362  if(bUseFrameSkip) \r
363   {\r
364    if(!(dwActFixes&0x100))\r
365     {\r
366      dwLaceCnt++;                                      // -> and store cnt of vsync between frames\r
367      if(dwLaceCnt>=MAXLACE && bUseFrameLimit) \r
368       {\r
369        if(dwLaceCnt==MAXLACE) bInitCap=TRUE;\r
370        FrameCap();\r
371       }\r
372     }\r
373    else if(bUseFrameLimit) FrameCap();\r
374    calcfps();                                          // -> calc fps display in skipping mode\r
375   }                                                  \r
376  else                                                  // -> non-skipping mode:\r
377   {\r
378    if(bUseFrameLimit) FrameCap();\r
379    if(ulKeybits&KEY_SHOWFPS) calcfps();  \r
380   }\r
381 }\r
382 \r
383 void CALLBACK GPUsetframelimit(unsigned long option)   // new EPSXE interface func: main emu can enable/disable fps limitation this way\r
384 {\r
385  bInitCap = TRUE;\r
386 \r
387  if(option==1)                                         // emu says: limit\r
388   {\r
389    bUseFrameLimit=TRUE;bUseFrameSkip=FALSE;iFrameLimit=2;\r
390    SetAutoFrameCap();\r
391   }\r
392  else                                                  // emu says: no limit\r
393   {\r
394    bUseFrameLimit=FALSE;\r
395   }\r
396 }\r