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. Da die CPU die Befehle erzeugen muss, um ein Frame zu rendern, benötigt diese Zeit auf der CPU und so entsteht bei hohen Frameraten entsprechend hohe Auslastung der CPU. 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 sehr hohen FPS läuft - wir bekommen davon sowieso nichts mit, außer niedriger Akkulaufzeit und hoher Stromrechnung. Abhängig von den Lichtquellen, die in der Umgebung strahlen sollte sollte man bis zu 120Hz als maximale FPS wählen, darunter kann es sonnst zu flimmern, oder Jitter Effekten kommen, wenn man das Auge schnell bewegt. Dieses Phänomen kann man üblicherweise bei Leuchtstoffröhren in Büros beobachten. Ein hoher Hertz(kurz Hz) Wert entspannt auch das Auge, so das es längere Zeiten vor dem Monitor ermöglicht, bevor der Augenapparat versagt und Zuckungen, Fokusprobleme und verzögertes Fokusieren als resultat zu folge hat. 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, andere dinge machen lässt. Diese Bildwiederholrate wird üblicherweise auf die aktuelle Monitor Frequenz gesetzt bzw. diese auch entsprechend angepasst. Der Monitor ist das schwächste Glied in der Kette und die unterstützen Frequenzen gehen bis zu 120Hz, bzw. höher, wenn diese 3D fähig sind.

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