fix some alignment issues
[pcsx_rearmed.git] / plugins / dfxvideo / fps.c
1 /***************************************************************************
2                           fps.c  -  description
3                              -------------------
4     begin                : Sun Oct 28 2001
5     copyright            : (C) 2001 by Pete Bernert
6     email                : BlackDove@addcom.de
7  ***************************************************************************/
8 /***************************************************************************
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version. See also the license.txt file for *
14  *   additional informations.                                              *
15  *                                                                         *
16  ***************************************************************************/
17
18 #define _IN_FPS
19
20 #include <unistd.h>
21
22 #include "externals.h"
23 #include "fps.h"
24 #include "gpu.h"
25
26 // FPS stuff
27 float          fFrameRateHz=0;
28 DWORD          dwFrameRateTicks=16;
29 float          fFrameRate;
30 int            iFrameLimit;
31 int            UseFrameLimit=0;
32 int            UseFrameSkip=0;
33
34 // FPS skipping / limit
35 BOOL   bInitCap = TRUE;
36 float  fps_skip = 0;
37 float  fps_cur  = 0;
38
39 #define MAXLACE 16
40
41 void CheckFrameRate(void)
42 {
43  if(UseFrameSkip)                                      // skipping mode?
44   {
45    if(!(dwActFixes&0x80))                              // not old skipping mode?
46     {
47      dwLaceCnt++;                                      // -> store cnt of vsync between frames
48      if(dwLaceCnt>=MAXLACE && UseFrameLimit)           // -> if there are many laces without screen toggling,
49       {                                                //    do std frame limitation
50        if(dwLaceCnt==MAXLACE) bInitCap=TRUE;
51        FrameCap();
52       }
53     }
54    else if(UseFrameLimit) FrameCap();
55    calcfps();                                          // -> calc fps display in skipping mode
56   }
57  else                                                  // non-skipping mode:
58   {
59    if(UseFrameLimit) FrameCap();                       // -> do it
60    if(ulKeybits&KEY_SHOWFPS) calcfps();                // -> and calc fps display
61   }
62 }
63
64 #define TIMEBASE 100000
65
66 unsigned long timeGetTime()
67 {
68  struct timeval tv;
69  gettimeofday(&tv, 0);                                 // well, maybe there are better ways
70  return tv.tv_sec * 100000 + tv.tv_usec/10;            // to do that, but at least it works
71 }
72
73 void FrameCap (void)
74 {
75  static unsigned long curticks, lastticks, _ticks_since_last_update;
76  static unsigned int TicksToWait = 0;
77  int overslept=0, tickstogo=0;
78  BOOL Waiting = TRUE;
79
80   {
81    curticks = timeGetTime();
82    _ticks_since_last_update = curticks - lastticks;
83
84     if((_ticks_since_last_update > TicksToWait) ||
85        (curticks <lastticks))
86     {
87      lastticks = curticks;
88      overslept = _ticks_since_last_update - TicksToWait;
89      if((_ticks_since_last_update-TicksToWait) > dwFrameRateTicks)
90           TicksToWait=0;
91      else
92           TicksToWait=dwFrameRateTicks - overslept;
93     }
94    else
95     {
96      while (Waiting)
97       {
98        curticks = timeGetTime();
99        _ticks_since_last_update = curticks - lastticks;
100        tickstogo = TicksToWait - _ticks_since_last_update;
101        if ((_ticks_since_last_update > TicksToWait) ||
102            (curticks < lastticks) || tickstogo < overslept)
103         {
104          Waiting = FALSE;
105          lastticks = curticks;
106          overslept = _ticks_since_last_update - TicksToWait;
107          TicksToWait = dwFrameRateTicks - overslept;
108          return;
109         }
110         if (tickstogo >= 200 && !(dwActFixes&16))
111                 usleep(tickstogo*10 - 200);
112       }
113     }
114   }
115 }
116
117 #define MAXSKIP 120
118
119 void FrameSkip(void)
120 {
121  static int   iNumSkips=0,iAdditionalSkip=0;           // number of additional frames to skip
122  static DWORD dwLastLace=0;                            // helper var for frame limitation
123  static DWORD curticks, lastticks, _ticks_since_last_update;
124  int tickstogo=0;
125  static int overslept=0;
126
127  if(!dwLaceCnt) return;                                // important: if no updatelace happened, we ignore it completely
128
129  if(iNumSkips)                                         // we are in skipping mode?
130   {
131    dwLastLace+=dwLaceCnt;                              // -> calc frame limit helper (number of laces)
132    bSkipNextFrame = TRUE;                              // -> we skip next frame
133    iNumSkips--;                                        // -> ok, one done
134   }
135  else                                                  // ok, no additional skipping has to be done...
136   {                                                    // we check now, if some limitation is needed, or a new skipping has to get started
137    DWORD dwWaitTime;
138
139    if(bInitCap || bSkipNextFrame)                      // first time or we skipped before?
140     {
141      if(UseFrameLimit && !bInitCap)                    // frame limit wanted and not first time called?
142       {
143        DWORD dwT=_ticks_since_last_update;             // -> that's the time of the last drawn frame
144        dwLastLace+=dwLaceCnt;                          // -> and that's the number of updatelace since the start of the last drawn frame
145
146        curticks = timeGetTime();                       // -> now we calc the time of the last drawn frame + the time we spent skipping
147        _ticks_since_last_update= dwT+curticks - lastticks;
148
149        dwWaitTime=dwLastLace*dwFrameRateTicks;         // -> and now we calc the time the real psx would have needed
150
151        if(_ticks_since_last_update<dwWaitTime)         // -> we were too fast?
152         {
153          if((dwWaitTime-_ticks_since_last_update)>     // -> some more security, to prevent
154             (60*dwFrameRateTicks))                     //    wrong waiting times
155           _ticks_since_last_update=dwWaitTime;
156
157          while(_ticks_since_last_update<dwWaitTime)    // -> loop until we have reached the real psx time
158           {                                            //    (that's the additional limitation, yup)
159            curticks = timeGetTime();
160            _ticks_since_last_update = dwT+curticks - lastticks;
161           }
162         }
163        else                                            // we were still too slow ?!!?
164         {
165          if(iAdditionalSkip<MAXSKIP)                   // -> well, somewhen we really have to stop skipping on very slow systems
166           {
167            iAdditionalSkip++;                          // -> inc our watchdog var
168            dwLaceCnt=0;                                // -> reset lace count
169            lastticks = timeGetTime();
170            return;                                     // -> done, we will skip next frame to get more speed
171           } 
172         }
173       }
174
175      bInitCap=FALSE;                                   // -> ok, we have inited the frameskip func
176      iAdditionalSkip=0;                                // -> init additional skip
177      bSkipNextFrame=FALSE;                             // -> we don't skip the next frame
178      lastticks = timeGetTime();                        // -> we store the start time of the next frame
179      dwLaceCnt=0;                                      // -> and we start to count the laces 
180      dwLastLace=0;
181      _ticks_since_last_update=0;
182      return;                                           // -> done, the next frame will get drawn
183     }
184
185    bSkipNextFrame=FALSE;                               // init the frame skip signal to 'no skipping' first
186
187    curticks = timeGetTime();                           // get the current time (we are now at the end of one drawn frame)
188    _ticks_since_last_update = curticks - lastticks;
189
190    dwLastLace=dwLaceCnt;                               // store curr count (frame limitation helper)
191    dwWaitTime=dwLaceCnt*dwFrameRateTicks;              // calc the 'real psx lace time'
192    if (dwWaitTime >= overslept)
193         dwWaitTime-=overslept;
194
195    if(_ticks_since_last_update>dwWaitTime)             // hey, we needed way too long for that frame...
196     {
197      if(UseFrameLimit)                                 // if limitation, we skip just next frame,
198       {                                                // and decide after, if we need to do more
199        iNumSkips=0;
200       }
201      else
202       {
203        iNumSkips=_ticks_since_last_update/dwWaitTime;  // -> calc number of frames to skip to catch up
204        iNumSkips--;                                    // -> since we already skip next frame, one down
205        if(iNumSkips>MAXSKIP) iNumSkips=MAXSKIP;        // -> well, somewhere we have to draw a line
206       }
207      bSkipNextFrame = TRUE;                            // -> signal for skipping the next frame
208     }
209    else                                                // we were faster than real psx? fine :)
210    if(UseFrameLimit)                                   // frame limit used? so we wait til the 'real psx time' has been reached
211     {
212      if(dwLaceCnt>MAXLACE)                             // -> security check
213       _ticks_since_last_update=dwWaitTime;
214
215      while(_ticks_since_last_update<dwWaitTime)        // -> just do a waiting loop...
216       {
217        curticks = timeGetTime();
218        _ticks_since_last_update = curticks - lastticks;
219
220         tickstogo = dwWaitTime - _ticks_since_last_update;
221         if (tickstogo-overslept >= 200 && !(dwActFixes&16))
222                 usleep(tickstogo*10 - 200);
223       }
224     }
225    overslept = _ticks_since_last_update - dwWaitTime;
226    if (overslept < 0)
227         overslept = 0;
228    lastticks = timeGetTime();                          // ok, start time of the next frame
229   }
230
231  dwLaceCnt=0;                                          // init lace counter
232 }
233
234 void calcfps(void)
235 {
236  static unsigned long curticks,_ticks_since_last_update,lastticks;
237  static long   fps_cnt = 0;
238  static unsigned long  fps_tck = 1;
239  static long          fpsskip_cnt = 0;
240  static unsigned long fpsskip_tck = 1;
241
242   {
243    curticks = timeGetTime();
244    _ticks_since_last_update=curticks-lastticks;
245
246    if(UseFrameSkip && !UseFrameLimit && _ticks_since_last_update)
247     fps_skip=min(fps_skip,((float)TIMEBASE/(float)_ticks_since_last_update+1.0f));
248
249    lastticks = curticks;
250   }
251
252  if(UseFrameSkip && UseFrameLimit)
253   {
254    fpsskip_tck += _ticks_since_last_update;
255
256    if(++fpsskip_cnt==2)
257     {
258      fps_skip = (float)2000/(float)fpsskip_tck;
259      fps_skip +=6.0f;
260      fpsskip_cnt = 0;
261      fpsskip_tck = 1;
262     }
263   }
264
265  fps_tck += _ticks_since_last_update;
266
267  if(++fps_cnt==20)
268   {
269    fps_cur = (float)(TIMEBASE*20)/(float)fps_tck;
270
271    fps_cnt = 0;
272    fps_tck = 1;
273
274    //if(UseFrameLimit && fps_cur>fFrameRateHz)           // optical adjust ;) avoids flickering fps display
275     //fps_cur=fFrameRateHz;
276   }
277
278 }
279
280 void PCFrameCap (void)
281 {
282  static unsigned long curticks, lastticks, _ticks_since_last_update;
283  static unsigned long TicksToWait = 0;
284  BOOL Waiting = TRUE;
285
286  while (Waiting)
287   {
288    curticks = timeGetTime();
289    _ticks_since_last_update = curticks - lastticks;
290    if ((_ticks_since_last_update > TicksToWait) ||
291        (curticks < lastticks))
292     {
293      Waiting = FALSE;
294      lastticks = curticks;
295      TicksToWait = (TIMEBASE/ (unsigned long)fFrameRateHz);
296     }
297   }
298 }
299
300 void PCcalcfps(void)
301 {
302  static unsigned long curticks,_ticks_since_last_update,lastticks;
303  static long  fps_cnt = 0;
304  static float fps_acc = 0;
305  float CurrentFPS=0;
306
307  curticks = timeGetTime();
308  _ticks_since_last_update=curticks-lastticks;
309  if(_ticks_since_last_update)
310       CurrentFPS=(float)TIMEBASE/(float)_ticks_since_last_update;
311  else CurrentFPS = 0;
312  lastticks = curticks;
313
314  fps_acc += CurrentFPS;
315
316  if(++fps_cnt==10)
317   {
318    fps_cur = fps_acc / 10;
319    fps_acc = 0;
320    fps_cnt = 0;
321   }
322
323  fps_skip=CurrentFPS+1.0f;
324 }
325
326 void SetAutoFrameCap(void)
327 {
328  if(iFrameLimit==1)
329   {
330    fFrameRateHz = fFrameRate;
331    dwFrameRateTicks=(TIMEBASE*100 / (unsigned long)(fFrameRateHz*100));
332    return;
333   }
334
335  if(dwActFixes&32)
336   {
337    if (PSXDisplay.Interlaced)
338         fFrameRateHz = PSXDisplay.PAL?50.0f:60.0f;
339    else fFrameRateHz = PSXDisplay.PAL?25.0f:30.0f;
340   }
341  else
342   {
343    fFrameRateHz = PSXDisplay.PAL?50.0f:59.94f;
344    dwFrameRateTicks=(TIMEBASE*100 / (unsigned long)(fFrameRateHz*100));
345   }
346 }
347
348 void SetFPSHandler(void)
349 {
350 }
351
352 void InitFPS(void)
353 {
354  if(!fFrameRate) fFrameRate=200.0f;
355  if(fFrameRateHz==0) fFrameRateHz=fFrameRate;          // set user framerate
356  dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz);
357 }