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