Frameratenbegrenzung
Inhaltsverzeichnis
Problemstellung
Bei vielen 3D-Anwendungen erfolgt die Bildausgabe so schnell hintereinander, wie die Hardware dies ermöglicht. Das bedeutet aber auch, dass die Auslastung des Computersystems auf 100% ansteigt. Das wiederum benötigt jede Menge Strom.
Unser Auge wiederum nimmt eine Bewegung ab ca. 20 Bildern pro Sekunde als flüssig wahr - es bringt also nicht sehr viel, wenn unsere Anwendung mit mehr als 1000FPS läuft - wir bekommen davon sowieso nichts mit. Die Lösung für dieses Problem ist eine Frameratenbegrenzung, die die Bildwiederholrate auf einen gewissen Wert limitiert und unsere Anwendung in der Zeit, in der nichts getan werden muss schlafen legt.
Ansatz
Die naive Lösung
Die einfachste Realisierung der Frameratenbegrenzung ist ein einfaches Hinzufügen der "Sleep" Anweisung in die Hauptschleife. Gehen wir von Sleep(5) aus, so haben wir eine Maximale Framerate von 200FPS. Diese Lösung ist jedoch etwas suboptimal. Gehen wir davon aus, das das Zeichnen der Inhalte an sich schon 5 Millisekunden dauert, so haben wir nur noch eine Framerate von 100FPS. Auf einem älterem Rechner könnte diese Berechnung auch länger dauern und die erreichte Framerate sich daher noch mehr von unserem anvisiertem Wert entfernen.
Die intelligente Lösung
Schlauer ist es, von der Zeit, die unser Programm pausiert, die Dauer des Rendervorgangs abzuziehen. Dazu ist es nötig, die Zeit, die zwischen zwei Frames vergeht zu messen. Um die Schlafenszeit nicht in dieser Messung zu haben, müssen wir uns diese natürlich merken und vorher abziehen. Mit diesem Ansatz passt sich die CPU-Auslastung an die Leistung des Systems an: Auf einem High-End PC wird sie automatisch niedriger als auf einem Rechner aus dem letztem Jahrhundert - so gehört es sich schließlich auch.
Implementierung
var FMaximumFrameRate: double; FLastSleep: double = 0; procedure LimitFrameRate(atd: double); //"atd" ist die Zeitdifferenz zwischen zwei Frames - inklusive der "Sleeptime" var sleeptime: Double; begin sleeptime := 1000 / FMaximumFrameRate - (atd - FLastSleep); if sleeptime > 0 then begin Sleep(trunc(sleeptime)); FLastSleep := sleeptime; end else FLastSleep := 0; end;