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