Frameratenbegrenzung

Aus DGL Wiki
Wechseln zu: Navigation, Suche

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. 24 Bildern pro Sekunde theoretisch als flüssig wahr - es bringt also nicht sehr viel, wenn unsere Anwendung mit mehr als 1000 FPS läuft - wir bekommen davon sowieso nichts mit, außer niedriger Akkulaufzeit und hoher Stromrechnung. 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, dass 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 anvisierten 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
    //statt sleep kann unter SDL auch SDL_Delay verwendet werden 
    Sleep(trunc(sleeptime));
    FLastSleep := sleeptime;
  end else
    FLastSleep := 0;
end;

Siehe auch

Framecounter
Framerate