Entwickler-Ecke

Algorithmen, Optimierung und Assembler - Framebuffer zu ungenau


Heiko - So 03.12.06 13:32
Titel: Framebuffer zu ungenau
Hallo,

ich habe mir einen kleinen FPS-Buffer gebaut, damit mein Programm keine FPS von 576 FPS mehr erreicht (also 100% CPU-Last), sondern nur noch maximal 100 (also aller 10 ms ein Bild). Wenn ich jetzt aber meinen FPS-Buffer drin habe, erreicht mein Source aber nur noch 56 FPS. Weiß einer von euch, wie man das Teil auf Genauigkeit trimmt?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
var
var
  t, nt: Cardinal;
begin
  //...
      nt:=GetTickCount;
      if nt<t+_mFPS then sleep(_mFPS+t-nt); //Framepuffer
      t:=nt;


//EDIT: _mFPS=1000 div FPS; (wenn ihr eine bessere Variante kennt, würde die mich echt interessieren ;) )


BenBE - So 03.12.06 13:54

Sleep nutzt die Systemzeitscheiben, die bei Windows ca. 20ms sind. Wenn Du wirklich genau 10ms haben willst, solltest Du QueryPerformanceCounter und QueryPerformanceFrequency verwenden. Damit geht das auf CPU-Takte genau (je nach Prozessor).

Der Aufwand dafür lohnt sich aber nicht wirklich ;-)


Heiko - So 03.12.06 13:58

Und was nehme ich da anstatt sleep?


Heiko - So 03.12.06 16:18

Ich muss mich berichtigen (hatte beim Debugg-String ein GetTickCount noch mit drin :mrgreen: ): Er läuft statt mit 100FPS mit 200 FPS ;). Also zu schnell...


F34r0fTh3D4rk - So 03.12.06 20:40

sleep in einem fps counter ? wozu das ? Oo

mfg


Heiko - So 03.12.06 20:45

Prozessorlast von 100% senken. Und da es ein Thread ist, stört es ja nicht ;).


F34r0fTh3D4rk - So 03.12.06 20:48

aso eine fps bremse sozusagen ;) ich dachte einen einfachen zähler ;)


Heiko - So 03.12.06 21:01

Jo. Ich habe auch schon den Fehler beseitigen können, allerdings mit dem Einkauf der Ungenauigkeit. Und zwar hatte ich nachm sleep die Zeit von vorm Sleep übergeben.

Es funzt jetzte so (aber leider besitzt es ne Ungenauigkeit, die ich nicht haben will...)

Delphi-Quelltext
1:
2:
3:
nt:=GetTickCount;
if nt-t<_mFPS then sleep(_mFPS-(nt-t)); //Framepuffer
t:=GetTickCount;


Alerdings funzt die genaue Variante auch nicht, wenn ich meinen Fehler "behebe" (den ich gefunden hatte):


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
nt:=GetTickCount;
if nt-t<_mFPS then
begin
  sleep(_mFPS-(nt-t)); //Framepuffer
  t:=t+_mFPS;
end
else t:=nt;


BenBE - Mo 04.12.06 06:09

Es gäbe für dich da vielleicht noch eine zweite Möglichkeit ... Zähl doch einfach Takte ;-)

Start:
- Frame# = 0
- FirstFrame = GetTickCount
- Auszählen, wie weit Du in 100ms Zählen kannst (Int64)

Für jedes Frame:
- GetTickCount - Frame# / WishFPS --> Aktueller Offset des Frames
- Wenn Offset mehr als 2 Frames zu früh: Sleep(50), IncsPerSec * 1.1
- Wenn Offset weniger als zwei Frame zu früh: Zählschleife bis IncsPerSec auf FPS-Zahl umgerechnet
- Wenn Frame mehr als halbe FPS-Zeit zu spät, dann IncsPerSec * 0.9
- Wenn IncsPerSec < 10 : IncsPerSec = 10

Der Algo adaptiert sich automatisch an die aktullen Verhältnisse und frisst auf schnellen Prozessoren nicht die volle Bandbreite, wenn man insgesamt den Algo darauf trimmt, dss er die Delay-Zeit zu kurz bestimmt und damit das Sleep(50) erreicht. Auf langsamen Prozessoren zieht dieser Algo gar keine Rechenzeit, da diese höchst wahrscheinlich meist im Rückstand sein werden.