adjust irq10 and rcnt for pal
[pcsx_rearmed.git] / plugins / gpu-gles / gpuFps.c
CommitLineData
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
49LARGE_INTEGER liCPUFrequency;\r
50#endif\r
51\r
52////////////////////////////////////////////////////////////////////////\r
53// FPS skipping / limit\r
54////////////////////////////////////////////////////////////////////////\r
55\r
56BOOL bIsPerformanceCounter;\r
57float fFrameRateHz;\r
58DWORD dwFrameRateTicks;\r
59float fFrameRate;\r
60int iFrameLimit;\r
61BOOL bUseFrameLimit;\r
62BOOL bUseFrameSkip;\r
63DWORD dwLaceCnt;\r
64\r
65BOOL bInitCap; \r
66float fps_skip;\r
67float fps_cur;\r
68\r
69#ifdef _WINDOWS\r
70\r
71void 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
199void 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
346void 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
424void 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
478void 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
530void 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
572void 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
581void 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
603void 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
625unsigned 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
632void 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
674void 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
781void 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
828void 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
850void 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
878void 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
916void 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
933void InitFrameCap(void)\r
934{\r
935 // nothing on linux\r
936}\r
937\r
938void 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
951void 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
976void 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