1 /***************************************************************************
2                           fps.c  -  description
3                              -------------------
4     begin                : Sun Mar 08 2009
5     copyright            : (C) 1999-2009 by Pete Bernert
6     web                  : www.pbernert.com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version. See also the license.txt file for *
15  *   additional informations.                                              *
16  *                                                                         *
17  ***************************************************************************/
18 
19 //*************************************************************************//
20 // History of changes:
21 //
22 // 2009/03/08 - Pete
23 // - generic cleanup for the Peops release
24 //
25 //*************************************************************************//
26 
27 #ifdef _WINDOWS
28 #include "Stdafx.h"
29 #include "Externals.h"
30 #include "plugin.h"
31 #include "Fps.h"
32 #include "Prim.h"
33 #else
34 #include "gpuStdafx.h"
35 #include "gpuExternals.h"
36 //#include "plugins.h"
37 #include "gpuFps.h"
38 #include "gpuPrim.h"
39 #endif
40 
41 #define _IN_FPS
42 
43 #define CALLBACK
44 
45 ////////////////////////////////////////////////////////////////////////
46 // FPS stuff
47 ////////////////////////////////////////////////////////////////////////
48 #ifdef _WINDOWS
49 LARGE_INTEGER  liCPUFrequency;
50 #endif
51 
52 ////////////////////////////////////////////////////////////////////////
53 // FPS skipping / limit
54 ////////////////////////////////////////////////////////////////////////
55 
56 BOOL           bIsPerformanceCounter;
57 float          fFrameRateHz;
58 DWORD          dwFrameRateTicks;
59 float          fFrameRate;
60 int            iFrameLimit;
61 BOOL           bUseFrameLimit;
62 BOOL           bUseFrameSkip;
63 DWORD          dwLaceCnt;
64 
65 BOOL         bInitCap;
66 float        fps_skip;
67 float        fps_cur;
68 
69 #ifdef _WINDOWS
70 
FrameCap(void)71 void FrameCap (void)
72 {
73  static DWORD curticks, lastticks, _ticks_since_last_update;
74  static DWORD TicksToWait = 0;
75  static LARGE_INTEGER  CurrentTime;
76  static LARGE_INTEGER  LastTime;
77  static BOOL SkipNextWait = FALSE;
78  BOOL Waiting = TRUE;
79 
80  //---------------------------------------------------------
81  // init some static vars...
82  // bInitCap is TRUE on startup and everytime the user
83  // is toggling the frame limit
84  //---------------------------------------------------------
85 
86  if(bInitCap)
87   {
88    bInitCap=FALSE;
89    if (bIsPerformanceCounter)
90     QueryPerformanceCounter(&LastTime);
91    lastticks = timeGetTime();
92    TicksToWait=0;
93    return;
94   }
95 
96  //---------------------------------------------------------
97 
98  if(bIsPerformanceCounter)
99   {
100    QueryPerformanceCounter(&CurrentTime);
101    _ticks_since_last_update = CurrentTime.LowPart - LastTime.LowPart;
102 
103    //---------------------------------------------------------
104    // check if diff > 1/2 sec, if yes: take mm timer value
105    //---------------------------------------------------------
106 
107    curticks = timeGetTime();
108    if(_ticks_since_last_update>(liCPUFrequency.LowPart>>1))
109     {
110      if(curticks < lastticks)
111           _ticks_since_last_update = dwFrameRateTicks+TicksToWait+1;
112      else _ticks_since_last_update = (liCPUFrequency.LowPart * (curticks - lastticks))/1000;
113     }
114 
115    //---------------------------------------------------------
116 
117    if ((_ticks_since_last_update > TicksToWait) ||
118        (CurrentTime.LowPart < LastTime.LowPart))
119     {
120      LastTime.HighPart = CurrentTime.HighPart;
121      LastTime.LowPart  = CurrentTime.LowPart;
122 
123      lastticks=curticks;
124 
125      if((_ticks_since_last_update-TicksToWait) > dwFrameRateTicks)
126           TicksToWait=0;
127      else TicksToWait=dwFrameRateTicks-(_ticks_since_last_update-TicksToWait);
128     }
129    else
130     {
131      while (Waiting)
132       {
133        QueryPerformanceCounter(&CurrentTime);
134        _ticks_since_last_update = CurrentTime.LowPart - LastTime.LowPart;
135 
136        //---------------------------------------------------------
137        // check if diff > 1/2 sec, if yes: take mm timer value
138        //---------------------------------------------------------
139        curticks = timeGetTime();
140        if(_ticks_since_last_update>(liCPUFrequency.LowPart>>1))
141         {
142          if(curticks < lastticks)
143               _ticks_since_last_update = TicksToWait+1;
144          else _ticks_since_last_update = (liCPUFrequency.LowPart * (curticks - lastticks))/1000;
145         }
146        //---------------------------------------------------------
147 
148        if ((_ticks_since_last_update > TicksToWait) ||
149            (CurrentTime.LowPart < LastTime.LowPart))
150         {
151          Waiting = FALSE;
152 
153          lastticks=curticks;
154 
155          LastTime.HighPart = CurrentTime.HighPart;
156          LastTime.LowPart = CurrentTime.LowPart;
157          TicksToWait = dwFrameRateTicks;
158         }
159       }
160     }
161   }
162  else
163   {
164    curticks = timeGetTime();
165    _ticks_since_last_update = curticks - lastticks;
166 
167    if ((_ticks_since_last_update > TicksToWait) ||
168        (curticks < lastticks))
169     {
170      lastticks = curticks;
171 
172      if((_ticks_since_last_update-TicksToWait) > dwFrameRateTicks)
173           TicksToWait=0;
174      else TicksToWait=dwFrameRateTicks-(_ticks_since_last_update-TicksToWait);
175     }
176    else
177     {
178      while (Waiting)
179       {
180        curticks = timeGetTime();
181        _ticks_since_last_update = curticks - lastticks;
182        if ((_ticks_since_last_update > TicksToWait) ||
183            (curticks < lastticks))
184         {
185          Waiting = FALSE;
186          lastticks = curticks;
187          TicksToWait = dwFrameRateTicks;
188         }
189       }
190     }
191   }
192 }
193 
194 ////////////////////////////////////////////////////////////////////////
195 
196 #define MAXSKIP 120
197 #define MAXLACE 16
198 
FrameSkip(void)199 void FrameSkip(void)
200 {
201  static int   iNumSkips=0,iAdditionalSkip=0;           // number of additional frames to skip
202  static DWORD dwLastLace=0;                            // helper var for frame limitation
203  static DWORD curticks, lastticks, _ticks_since_last_update;
204  static LARGE_INTEGER  CurrentTime;
205  static LARGE_INTEGER  LastTime;
206 
207  if(!dwLaceCnt) return;                                // important: if no updatelace happened, we ignore it completely
208 
209  if(iNumSkips)                                         // we are in skipping mode?
210   {
211    dwLastLace+=dwLaceCnt;                              // -> calc frame limit helper (number of laces)
212    bSkipNextFrame = TRUE;                              // -> we skip next frame
213    iNumSkips--;                                        // -> ok, one done
214   }
215  else                                                  // ok, no additional skipping has to be done...
216   {                                                    // we check now, if some limitation is needed, or a new skipping has to get started
217    DWORD dwWaitTime;
218 
219    if(bInitCap || bSkipNextFrame)                      // first time or we skipped before?
220     {
221      if(bUseFrameLimit && !bInitCap)                   // frame limit wanted and not first time called?
222       {
223        DWORD dwT=_ticks_since_last_update;             // -> that's the time of the last drawn frame
224        dwLastLace+=dwLaceCnt;                          // -> and that's the number of updatelace since the start of the last drawn frame
225 
226        if(bIsPerformanceCounter)                       // -> now we calc the time of the last drawn frame + the time we spent skipping
227         {
228          QueryPerformanceCounter(&CurrentTime);
229          _ticks_since_last_update= dwT+CurrentTime.LowPart - LastTime.LowPart;
230         }
231        else
232         {
233          curticks = timeGetTime();
234          _ticks_since_last_update= dwT+curticks - lastticks;
235         }
236 
237        dwWaitTime=dwLastLace*dwFrameRateTicks;         // -> and now we calc the time the real psx would have needed
238 
239        if(_ticks_since_last_update<dwWaitTime)         // -> we were too fast?
240         {
241          if((dwWaitTime-_ticks_since_last_update)>     // -> some more security, to prevent
242             (60*dwFrameRateTicks))                     //    wrong waiting times
243           _ticks_since_last_update=dwWaitTime;
244 
245          while(_ticks_since_last_update<dwWaitTime)    // -> loop until we have reached the real psx time
246           {                                            //    (that's the additional limitation, yup)
247            if(bIsPerformanceCounter)
248             {
249              QueryPerformanceCounter(&CurrentTime);
250              _ticks_since_last_update = dwT+CurrentTime.LowPart - LastTime.LowPart;
251             }
252            else
253             {
254              curticks = timeGetTime();
255              _ticks_since_last_update = dwT+curticks - lastticks;
256             }
257           }
258         }
259        else                                            // we were still too slow ?!!?
260         {
261          if(iAdditionalSkip<MAXSKIP)                   // -> well, somewhen we really have to stop skipping on very slow systems
262           {
263            iAdditionalSkip++;                          // -> inc our watchdog var
264            dwLaceCnt=0;                                // -> reset lace count
265            if(bIsPerformanceCounter)                   // -> ok, start time of the next frame
266             QueryPerformanceCounter(&LastTime);
267            lastticks = timeGetTime();
268            return;                                     // -> done, we will skip next frame to get more speed
269           }
270         }
271       }
272 
273      bInitCap=FALSE;                                   // -> ok, we have inited the frameskip func
274      iAdditionalSkip=0;                                // -> init additional skip
275      bSkipNextFrame=FALSE;                              // -> we don't skip the next frame
276      if(bIsPerformanceCounter)                         // -> we store the start time of the next frame
277       QueryPerformanceCounter(&LastTime);
278      lastticks = timeGetTime();
279      dwLaceCnt=0;                                      // -> and we start to count the laces
280      dwLastLace=0;
281      _ticks_since_last_update=0;
282      return;                                           // -> done, the next frame will get drawn
283     }
284 
285    bSkipNextFrame=FALSE;                                // init the frame skip signal to 'no skipping' first
286 
287    if(bIsPerformanceCounter)                           // get the current time (we are now at the end of one drawn frame)
288     {
289      QueryPerformanceCounter(&CurrentTime);
290      _ticks_since_last_update = CurrentTime.LowPart - LastTime.LowPart;
291     }
292    else
293     {
294      curticks = timeGetTime();
295      _ticks_since_last_update = curticks - lastticks;
296     }
297 
298    dwLastLace=dwLaceCnt;                               // store curr count (frame limitation helper)
299    dwWaitTime=dwLaceCnt*dwFrameRateTicks;              // calc the 'real psx lace time'
300 
301    if(_ticks_since_last_update>dwWaitTime)             // hey, we needed way too long for that frame...
302     {
303      if(bUseFrameLimit)                                // if limitation, we skip just next frame,
304       {                                                // and decide after, if we need to do more
305        iNumSkips=0;
306       }
307      else
308       {
309        iNumSkips=_ticks_since_last_update/dwWaitTime;  // -> calc number of frames to skip to catch up
310        iNumSkips--;                                    // -> since we already skip next frame, one down
311        if(iNumSkips>MAXSKIP) iNumSkips=MAXSKIP;        // -> well, somewhere we have to draw a line
312       }
313      bSkipNextFrame = TRUE;                            // -> signal for skipping the next frame
314     }
315    else                                                // we were faster than real psx? fine :)
316    if(bUseFrameLimit)                                  // frame limit used? so we wait til the 'real psx time' has been reached
317     {
318      if(dwLaceCnt>MAXLACE)                             // -> security check
319       _ticks_since_last_update=dwWaitTime;
320 
321      while(_ticks_since_last_update<dwWaitTime)        // just do a waiting loop...
322       {
323        if(bIsPerformanceCounter)
324         {
325          QueryPerformanceCounter(&CurrentTime);
326          _ticks_since_last_update = CurrentTime.LowPart - LastTime.LowPart;
327         }
328        else
329         {
330          curticks = timeGetTime();
331          _ticks_since_last_update = curticks - lastticks;
332         }
333       }
334     }
335 
336    if(bIsPerformanceCounter)                           // ok, start time of the next frame
337     QueryPerformanceCounter(&LastTime);
338    lastticks = timeGetTime();
339   }
340 
341  dwLaceCnt=0;                                          // init lace counter
342 }
343 
344 ////////////////////////////////////////////////////////////////////////
345 
calcfps(void)346 void calcfps(void)
347 {
348  static DWORD curticks,_ticks_since_last_update,lastticks;
349  static long   fps_cnt = 0;
350  static DWORD  fps_tck = 1;
351  static LARGE_INTEGER  CurrentTime;
352  static LARGE_INTEGER  LastTime;
353  static long   fpsskip_cnt = 0;
354  static DWORD  fpsskip_tck = 1;
355 
356  if(bIsPerformanceCounter)
357   {
358    QueryPerformanceCounter(&CurrentTime);
359    _ticks_since_last_update=CurrentTime.LowPart-LastTime.LowPart;
360 
361    //--------------------------------------------------//
362    curticks = timeGetTime();
363    if(_ticks_since_last_update>(liCPUFrequency.LowPart>>1))
364     _ticks_since_last_update = (liCPUFrequency.LowPart * (curticks - lastticks))/1000;
365    lastticks=curticks;
366    //--------------------------------------------------//
367 
368    if(bUseFrameSkip && !bUseFrameLimit && _ticks_since_last_update)
369     fps_skip=min(fps_skip,(((float)liCPUFrequency.LowPart) / ((float)_ticks_since_last_update) +1.0f));
370 
371    LastTime.HighPart = CurrentTime.HighPart;
372    LastTime.LowPart = CurrentTime.LowPart;
373   }
374  else
375   {
376    curticks = timeGetTime();
377    _ticks_since_last_update=curticks-lastticks;
378 
379    if(bUseFrameSkip && !bUseFrameLimit && _ticks_since_last_update)
380     fps_skip=min(fps_skip,((float)1000/(float)_ticks_since_last_update+1.0f));
381 
382    lastticks = curticks;
383   }
384 
385  if(bUseFrameSkip && bUseFrameLimit)
386   {
387    fpsskip_tck += _ticks_since_last_update;
388 
389    if(++fpsskip_cnt==2)
390     {
391      if(bIsPerformanceCounter)
392       fps_skip = ((float)liCPUFrequency.LowPart) / ((float)fpsskip_tck) *2.0f;
393      else
394       fps_skip = (float)2000/(float)fpsskip_tck;
395 
396      fps_skip +=6.0f;
397 
398      fpsskip_cnt = 0;
399      fpsskip_tck = 1;
400     }
401   }
402 
403  fps_tck += _ticks_since_last_update;
404 
405  if(++fps_cnt==10)
406   {
407    if(bIsPerformanceCounter)
408     fps_cur = ((float)liCPUFrequency.LowPart) / ((float)fps_tck) *10.0f;
409    else
410     fps_cur = (float)10000/(float)fps_tck;
411 
412    fps_cnt = 0;
413    fps_tck = 1;
414 
415    if(bUseFrameLimit && fps_cur>fFrameRateHz)            // optical adjust ;) avoids flickering fps display
416     fps_cur=fFrameRateHz;
417   }
418 }
419 
420 ////////////////////////////////////////////////////////////////////////
421 // PC FPS skipping / limit
422 ////////////////////////////////////////////////////////////////////////
423 
PCFrameCap(void)424 void PCFrameCap(void)
425 {
426  static DWORD curticks, lastticks, _ticks_since_last_update;
427  static DWORD TicksToWait = 0;
428  static LARGE_INTEGER  CurrentTime;
429  static LARGE_INTEGER  LastTime;
430  BOOL Waiting = TRUE;
431 
432  while (Waiting)
433   {
434    if(bIsPerformanceCounter)
435     {
436      QueryPerformanceCounter(&CurrentTime);
437      _ticks_since_last_update = CurrentTime.LowPart - LastTime.LowPart;
438 
439      //------------------------------------------------//
440      curticks = timeGetTime();
441      if(_ticks_since_last_update>(liCPUFrequency.LowPart>>1))
442       {
443        if(curticks < lastticks)
444             _ticks_since_last_update = TicksToWait+1;
445        else _ticks_since_last_update = (liCPUFrequency.LowPart * (curticks - lastticks))/1000;
446       }
447      //------------------------------------------------//
448 
449      if ((_ticks_since_last_update > TicksToWait) ||
450          (CurrentTime.LowPart < LastTime.LowPart))
451       {
452        Waiting = FALSE;
453 
454        lastticks=curticks;
455 
456        LastTime.HighPart = CurrentTime.HighPart;
457        LastTime.LowPart = CurrentTime.LowPart;
458        TicksToWait = (liCPUFrequency.LowPart / fFrameRateHz);
459       }
460     }
461    else
462     {
463      curticks = timeGetTime();
464      _ticks_since_last_update = curticks - lastticks;
465      if ((_ticks_since_last_update > TicksToWait) ||
466          (curticks < lastticks))
467       {
468        Waiting = FALSE;
469        lastticks = curticks;
470        TicksToWait = (1000 / (DWORD)fFrameRateHz);
471       }
472     }
473   }
474 }
475 
476 ////////////////////////////////////////////////////////////////////////
477 
PCcalcfps(void)478 void PCcalcfps(void)
479 {
480  static DWORD curticks,_ticks_since_last_update,lastticks;
481  static long  fps_cnt = 0;
482  static float fps_acc = 0;
483  static LARGE_INTEGER  CurrentTime;
484  static LARGE_INTEGER  LastTime;
485  float CurrentFPS=0;
486 
487  if(bIsPerformanceCounter)
488   {
489    QueryPerformanceCounter(&CurrentTime);
490    _ticks_since_last_update=CurrentTime.LowPart-LastTime.LowPart;
491 
492    //--------------------------------------------------//
493    curticks = timeGetTime();
494    if(_ticks_since_last_update>(liCPUFrequency.LowPart>>1))
495     _ticks_since_last_update = (liCPUFrequency.LowPart * (curticks - lastticks))/1000;
496    lastticks=curticks;
497    //--------------------------------------------------//
498 
499    if(_ticks_since_last_update)
500     {
501      CurrentFPS = ((float)liCPUFrequency.LowPart) / ((float)_ticks_since_last_update);
502     }
503    else CurrentFPS = 0;
504    LastTime.HighPart = CurrentTime.HighPart;
505    LastTime.LowPart = CurrentTime.LowPart;
506   }
507  else
508   {
509    curticks = timeGetTime();
510    if(_ticks_since_last_update=curticks-lastticks)
511         CurrentFPS=(float)1000/(float)_ticks_since_last_update;
512    else CurrentFPS = 0;
513    lastticks = curticks;
514   }
515 
516  fps_acc += CurrentFPS;
517 
518  if(++fps_cnt==10)
519   {
520    fps_cur = fps_acc / 10;
521    fps_acc = 0;
522    fps_cnt = 0;
523   }
524 
525  fps_skip=CurrentFPS+1.0f;
526 }
527 
528 ////////////////////////////////////////////////////////////////////////
529 
SetAutoFrameCap(void)530 void SetAutoFrameCap(void)
531 {
532  if(iFrameLimit==1)
533   {
534    fFrameRateHz = fFrameRate;
535    if(bIsPerformanceCounter)
536         dwFrameRateTicks=(liCPUFrequency.LowPart / fFrameRateHz);
537    else dwFrameRateTicks=(1000 / (DWORD)fFrameRateHz);
538    return;
539   }
540 
541  if(dwActFixes&128)
542   {
543    if (PSXDisplay.Interlaced)
544         fFrameRateHz = PSXDisplay.PAL?50.0f:60.0f;
545    else fFrameRateHz = PSXDisplay.PAL?25.0f:30.0f;
546   }
547  else
548   {
549    //fFrameRateHz = PSXDisplay.PAL?50.0f:59.94f;
550 
551    if(PSXDisplay.PAL)
552     {
553      if (STATUSREG&GPUSTATUS_INTERLACED)
554            fFrameRateHz=33868800.0f/677343.75f;        // 50.00238
555       else fFrameRateHz=33868800.0f/680595.00f;        // 49.76351
556     }
557    else
558     {
559      if (STATUSREG&GPUSTATUS_INTERLACED)
560            fFrameRateHz=33868800.0f/565031.25f;        // 59.94146
561       else fFrameRateHz=33868800.0f/566107.50f;        // 59.82750
562     }
563 
564    if(bIsPerformanceCounter)
565         dwFrameRateTicks=(liCPUFrequency.LowPart / fFrameRateHz);
566    else dwFrameRateTicks=(1000 / (DWORD)fFrameRateHz);
567   }
568 }
569 
570 ////////////////////////////////////////////////////////////////////////
571 
InitFrameCap(void)572 void InitFrameCap(void)                                // inits cpu frequency info (on gpu startup)
573 {
574  if (QueryPerformanceFrequency (&liCPUFrequency))
575       bIsPerformanceCounter = TRUE;
576  else bIsPerformanceCounter = FALSE;
577 }
578 
579 ////////////////////////////////////////////////////////////////////////
580 
ReInitFrameCap(void)581 void ReInitFrameCap(void)
582 {
583  BOOL bOldPerformanceCounter=bIsPerformanceCounter;    // store curr timer mode
584 
585  if(dwActFixes&0x10000)                                // check game fix... high performance counters are bad on some mb chipsets
586       bIsPerformanceCounter=FALSE;
587  else
588   {
589    if (QueryPerformanceFrequency (&liCPUFrequency))
590         bIsPerformanceCounter = TRUE;
591    else bIsPerformanceCounter = FALSE;
592   }
593 
594  if(bOldPerformanceCounter!=bIsPerformanceCounter)     // changed?
595   {
596    bInitCap = TRUE;
597    SetAutoFrameCap();
598   }
599 }
600 
601 ////////////////////////////////////////////////////////////////////////
602 
SetFrameRateConfig(void)603 void SetFrameRateConfig(void)
604 {
605  if(fFrameRateHz==0)
606   {
607    if(iFrameLimit==2) fFrameRateHz=59.94f;           // auto framerate? set some init val (no pal/ntsc known yet)
608    else               fFrameRateHz=fFrameRate;       // else set user framerate
609   }
610 
611  if(bIsPerformanceCounter)
612       dwFrameRateTicks=(liCPUFrequency.LowPart / fFrameRateHz);
613  else dwFrameRateTicks=(1000 / (DWORD)fFrameRateHz);
614 }
615 
616 ////////////////////////////////////////////////////////////////////////
617 
618 // LINUX ---------------------------------------------
619 
620 #else
621 
622 #define TIMEBASE 100000
623 
624 // hehehe... using same func name as with win32 ;) wow, are we genius ;)
timeGetTime()625 unsigned long timeGetTime()
626 {
627  struct timeval tv;
628  gettimeofday(&tv, 0);                                // well, maybe there are better ways
629  return tv.tv_sec * 100000 + tv.tv_usec/10;           // to do that in linux, but at least it works
630 }
631 
FrameCap(void)632 void FrameCap(void)
633 {
634  static unsigned long curticks, lastticks, _ticks_since_last_update;
635  static unsigned long TicksToWait = 0;
636  bool Waiting = TRUE;
637 
638   {
639    curticks = timeGetTime();
640    _ticks_since_last_update = curticks - lastticks;
641 
642     if((_ticks_since_last_update > TicksToWait) ||
643        (curticks <lastticks))
644     {
645      lastticks = curticks;
646 
647      if((_ticks_since_last_update-TicksToWait) > dwFrameRateTicks)
648           TicksToWait=0;
649      else TicksToWait=dwFrameRateTicks-(_ticks_since_last_update-TicksToWait);
650     }
651    else
652     {
653      while (Waiting)
654       {
655        curticks = timeGetTime();
656        _ticks_since_last_update = curticks - lastticks;
657        if ((_ticks_since_last_update > TicksToWait) ||
658            (curticks < lastticks))
659         {
660          Waiting = FALSE;
661          lastticks = curticks;
662          TicksToWait = dwFrameRateTicks;
663         }
664       }
665     }
666   }
667 }
668 
669 ////////////////////////////////////////////////////////////////////////
670 
671 #define MAXSKIP 120
672 #define MAXLACE 16
673 
FrameSkip(void)674 void FrameSkip(void)
675 {
676  static int   iNumSkips=0,iAdditionalSkip=0;           // number of additional frames to skip
677  static DWORD dwLastLace=0;                            // helper var for frame limitation
678  static DWORD curticks, lastticks, _ticks_since_last_update;
679 
680  if(!dwLaceCnt) return;                                // important: if no updatelace happened, we ignore it completely
681 
682  if(iNumSkips)                                         // we are in skipping mode?
683   {
684    dwLastLace+=dwLaceCnt;                              // -> calc frame limit helper (number of laces)
685    bSkipNextFrame = TRUE;                              // -> we skip next frame
686    iNumSkips--;                                        // -> ok, one done
687   }
688  else                                                  // ok, no additional skipping has to be done...
689   {                                                    // we check now, if some limitation is needed, or a new skipping has to get started
690    DWORD dwWaitTime;
691 
692    if(bInitCap || bSkipNextFrame)                      // first time or we skipped before?
693     {
694      if(bUseFrameLimit && !bInitCap)                   // frame limit wanted and not first time called?
695       {
696        DWORD dwT=_ticks_since_last_update;             // -> that's the time of the last drawn frame
697        dwLastLace+=dwLaceCnt;                          // -> and that's the number of updatelace since the start of the last drawn frame
698 
699        curticks = timeGetTime();
700        _ticks_since_last_update= dwT+curticks - lastticks;
701 
702        dwWaitTime=dwLastLace*dwFrameRateTicks;         // -> and now we calc the time the real psx would have needed
703 
704        if(_ticks_since_last_update<dwWaitTime)         // -> we were too fast?
705         {
706          if((dwWaitTime-_ticks_since_last_update)>     // -> some more security, to prevent
707             (60*dwFrameRateTicks))                     //    wrong waiting times
708           _ticks_since_last_update=dwWaitTime;
709 
710          while(_ticks_since_last_update<dwWaitTime)    // -> loop until we have reached the real psx time
711           {                                            //    (that's the additional limitation, yup)
712            curticks = timeGetTime();
713            _ticks_since_last_update = dwT+curticks - lastticks;
714           }
715         }
716        else                                            // we were still too slow ?!!?
717         {
718          if(iAdditionalSkip<MAXSKIP)                   // -> well, somewhen we really have to stop skipping on very slow systems
719           {
720            iAdditionalSkip++;                          // -> inc our watchdog var
721            dwLaceCnt=0;                                // -> reset lace count
722            lastticks = timeGetTime();
723            return;                                     // -> done, we will skip next frame to get more speed
724           }
725         }
726       }
727 
728      bInitCap=FALSE;                                   // -> ok, we have inited the frameskip func
729      iAdditionalSkip=0;                                // -> init additional skip
730      bSkipNextFrame=FALSE;                             // -> we don't skip the next frame
731      lastticks = timeGetTime();
732      dwLaceCnt=0;                                      // -> and we start to count the laces
733      dwLastLace=0;
734      _ticks_since_last_update=0;
735      return;                                           // -> done, the next frame will get drawn
736     }
737 
738    bSkipNextFrame=FALSE;                               // init the frame skip signal to 'no skipping' first
739 
740    curticks = timeGetTime();
741    _ticks_since_last_update = curticks - lastticks;
742 
743    dwLastLace=dwLaceCnt;                               // store curr count (frame limitation helper)
744    dwWaitTime=dwLaceCnt*dwFrameRateTicks;              // calc the 'real psx lace time'
745 
746    if(_ticks_since_last_update>dwWaitTime)             // hey, we needed way too long for that frame...
747     {
748      if(bUseFrameLimit)                                // if limitation, we skip just next frame,
749       {                                                // and decide after, if we need to do more
750        iNumSkips=0;
751       }
752      else
753       {
754        iNumSkips=_ticks_since_last_update/dwWaitTime;  // -> calc number of frames to skip to catch up
755        iNumSkips--;                                    // -> since we already skip next frame, one down
756        if(iNumSkips>MAXSKIP) iNumSkips=MAXSKIP;        // -> well, somewhere we have to draw a line
757       }
758      bSkipNextFrame = TRUE;                            // -> signal for skipping the next frame
759     }
760    else                                                // we were faster than real psx? fine :)
761    if(bUseFrameLimit)                                  // frame limit used? so we wait til the 'real psx time' has been reached
762     {
763      if(dwLaceCnt>MAXLACE)                             // -> security check
764       _ticks_since_last_update=dwWaitTime;
765 
766      while(_ticks_since_last_update<dwWaitTime)        // just do a waiting loop...
767       {
768        curticks = timeGetTime();
769        _ticks_since_last_update = curticks - lastticks;
770       }
771     }
772 
773    lastticks = timeGetTime();
774   }
775 
776  dwLaceCnt=0;                                          // init lace counter
777 }
778 
779 ////////////////////////////////////////////////////////////////////////
780 
calcfps(void)781 void calcfps(void)
782 {
783  static unsigned long curticks,_ticks_since_last_update,lastticks;
784  static long   fps_cnt = 0;
785  static unsigned long  fps_tck = 1;
786  static long           fpsskip_cnt = 0;
787  static unsigned long  fpsskip_tck = 1;
788 
789   {
790    curticks = timeGetTime();
791    _ticks_since_last_update=curticks-lastticks;
792 
793    if(bUseFrameSkip && !bUseFrameLimit && _ticks_since_last_update)
794     fps_skip=min(fps_skip,((float)TIMEBASE/(float)_ticks_since_last_update+1.0f));
795 
796    lastticks = curticks;
797   }
798 
799  if(bUseFrameSkip && bUseFrameLimit)
800   {
801    fpsskip_tck += _ticks_since_last_update;
802 
803    if(++fpsskip_cnt==2)
804     {
805      fps_skip = (float)2000/(float)fpsskip_tck;
806 
807      fps_skip +=6.0f;
808 
809      fpsskip_cnt = 0;
810      fpsskip_tck = 1;
811     }
812   }
813 
814  fps_tck += _ticks_since_last_update;
815 
816  if(++fps_cnt==10)
817   {
818    fps_cur = (float)(TIMEBASE*10)/(float)fps_tck;
819 
820    fps_cnt = 0;
821    fps_tck = 1;
822 
823    if(bUseFrameLimit && fps_cur>fFrameRateHz)            // optical adjust ;) avoids flickering fps display
824     fps_cur=fFrameRateHz;
825   }
826 }
827 
PCFrameCap(void)828 void PCFrameCap (void)
829 {
830  static unsigned long curticks, lastticks, _ticks_since_last_update;
831  static unsigned long TicksToWait = 0;
832  bool Waiting = TRUE;
833 
834  while (Waiting)
835   {
836    curticks = timeGetTime();
837    _ticks_since_last_update = curticks - lastticks;
838    if ((_ticks_since_last_update > TicksToWait) ||
839        (curticks < lastticks))
840     {
841      Waiting = FALSE;
842      lastticks = curticks;
843      TicksToWait = (TIMEBASE / (unsigned long)fFrameRateHz);
844     }
845   }
846 }
847 
848 ////////////////////////////////////////////////////////////////////////
849 
PCcalcfps(void)850 void PCcalcfps(void)
851 {
852  static unsigned long curticks,_ticks_since_last_update,lastticks;
853  static long  fps_cnt = 0;
854  static float fps_acc = 0;
855  float CurrentFPS=0;
856 
857  curticks = timeGetTime();
858  _ticks_since_last_update=curticks-lastticks;
859  if(_ticks_since_last_update)
860       CurrentFPS=(float)TIMEBASE/(float)_ticks_since_last_update;
861  else CurrentFPS = 0;
862  lastticks = curticks;
863 
864  fps_acc += CurrentFPS;
865 
866  if(++fps_cnt==10)
867   {
868    fps_cur = fps_acc / 10;
869    fps_acc = 0;
870    fps_cnt = 0;
871   }
872 
873  fps_skip=CurrentFPS+1.0f;
874 }
875 
876 ////////////////////////////////////////////////////////////////////////
877 
SetAutoFrameCap(void)878 void SetAutoFrameCap(void)
879 {
880  if(iFrameLimit==1)
881   {
882    fFrameRateHz = fFrameRate;
883    dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz);
884    return;
885   }
886 
887  if(dwActFixes&128)
888   {
889    if (PSXDisplay.Interlaced)
890         fFrameRateHz = PSXDisplay.PAL?50.0f:60.0f;
891    else fFrameRateHz = PSXDisplay.PAL?25.0f:30.0f;
892   }
893  else
894   {
895    //fFrameRateHz = PSXDisplay.PAL?50.0f:59.94f;
896 
897    if(PSXDisplay.PAL)
898     {
899      if (STATUSREG&GPUSTATUS_INTERLACED)
900            fFrameRateHz=33868800.0f/677343.75f;        // 50.00238
901       else fFrameRateHz=33868800.0f/680595.00f;        // 49.76351
902     }
903    else
904     {
905      if (STATUSREG&GPUSTATUS_INTERLACED)
906            fFrameRateHz=33868800.0f/565031.25f;        // 59.94146
907       else fFrameRateHz=33868800.0f/566107.50f;        // 59.82750
908     }
909 
910    dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz);
911   }
912 }
913 
914 ////////////////////////////////////////////////////////////////////////
915 
SetFrameRateConfig(void)916 void SetFrameRateConfig(void)
917 {
918  if(!fFrameRate) fFrameRate=200.0f;
919 
920  if(fFrameRateHz==0)
921   {
922    if(iFrameLimit==2) fFrameRateHz=59.94f;             // auto framerate? set some init val (no pal/ntsc known yet)
923    else               fFrameRateHz=fFrameRate;         // else set user framerate
924   }
925 
926  dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz);
927 
928  if(iFrameLimit==2) SetAutoFrameCap();
929 }
930 
931 ////////////////////////////////////////////////////////////////////////
932 
InitFrameCap(void)933 void InitFrameCap(void)
934 {
935  // nothing on linux
936 }
937 
ReInitFrameCap(void)938 void ReInitFrameCap(void)
939 {
940  // nothing on linux
941 }
942 
943 ////////////////////////////////////////////////////////////////////////
944 
945 #endif
946 
947 ////////////////////////////////////////////////////////////////////////
948 
949 ////////////////////////////////////////////////////////////////////////
950 
CheckFrameRate(void)951 void CheckFrameRate(void)                              // called in updatelace (on every emulated psx vsync)
952 {
953  if(bUseFrameSkip)
954   {
955    if(!(dwActFixes&0x100))
956     {
957      dwLaceCnt++;                                      // -> and store cnt of vsync between frames
958      if(dwLaceCnt>=MAXLACE && bUseFrameLimit)
959       {
960        if(dwLaceCnt==MAXLACE) bInitCap=TRUE;
961        FrameCap();
962       }
963     }
964    else if(bUseFrameLimit) FrameCap();
965    calcfps();                                          // -> calc fps display in skipping mode
966   }
967  else                                                  // -> non-skipping mode:
968   {
969    if(bUseFrameLimit) FrameCap();
970    calcfps();
971   }
972 }
973 
974 ////////////////////////////////////////////////////////////////////////
975 
GPUsetframelimit(unsigned long option)976 void CALLBACK GPUsetframelimit(unsigned long option)   // new EPSXE interface func: main emu can enable/disable fps limitation this way
977 {
978  bInitCap = TRUE;
979 
980  if(option==1)                                         // emu says: limit
981   {
982    bUseFrameLimit=TRUE;bUseFrameSkip=FALSE;iFrameLimit=2;
983    SetAutoFrameCap();
984   }
985  else                                                  // emu says: no limit
986   {
987    bUseFrameLimit=FALSE;
988   }
989 }
990 
991 ////////////////////////////////////////////////////////////////////////
992