Hello, Guest the thread was called2.2k times and contains 109 replays

last post from PiCiJi at the

Eingabe Latenzen in Emulatoren

  • Um die Eingabe Latenz in Denise zu verbessern, stelle ich verschiedene Möglichkeiten vor um dies zu erreichen. Da Verbesserungen zu diesem Thema doch sehr subjektiv sind, hoffe ich auf ein paar eingefleischte C64 Zocker, denen das Thema wichtig ist und die entstehenden Umbauten testen/vergleichen und dann ihre Erfahrungen hier teilen.


    das Problem

    Emulatoren haben im Gegensatz zum Original Gerät eine subjektiv wahrnehmbare Latenz zwischen Eingabe und Verarbeitung. Die Gründe dafür sind hauptsächlich im OS (der lange Weg durchs OS), dem LCD und den USB Geräten zu suchen.

    Die Ergebnisse schwanken mit den verwendeten Geräten. Extrem Spieler achten hier besonders auf USB Joypads mit hohen Abtast Raten.

    Es gibt Spieler die aufgrund dieser Latenz in der Emulation nicht die gleichen Resultate erreichen, wie am Original Gerät.

    Die meisten Emulatoren (Gast) tasten die am PC/Mac (Host) angeschlossenen Geräte zwischen den Bildern ab. Programme prüfen in der Regel im Rahmen Bereich oder Vertical blanking, also nach dem sichtbaren Teil des Bildes, die Eingabegeräte.

    Abhängig davon, wann die emulierten Programme die Eingabe prüfen, kann zwischen Host und Gast Abtastung fast ein komplettes Bild verstrichen sein. Somit ist es nicht selten, das zur natürlichen Eingabe Latenz noch ein weiteres Bild die Erkennung der Eingabe verpasst wird.


    welche Techniken gibt es


    - aggressives Abtasten der Eingabe in jeder Bildzeile

    Es gibt tatsächlich Emulatoren, die das tun. Aus meiner Sicht ist das eine ziemliche Performance Verschwendung. Die besten USB Geräte tasten mit einer Rate von 1000Hz ab, üblich sind jedoch um die 100Hz.


    - Just in Time Polling (Hiermit beginne ich.)

    Bei dieser Technik tastet der Host erst ab, wenn der Gast auch tatsächlich auf die Controller zugreifen will. Auf diese Weise ist das Abtasten zwischen Host und Gast sehr dicht beieinander. Sinnvoll ist bei weiterem Abtasten des Gastes,

    den Host nicht nach zu kurz verstrichener Zeit erneut abtasten zu lassen. Das würde nur Performance verschwenden aber keine Änderungen bringen. Ein weiteres Abtasten des Hostes sollte erst in frühstens 5 ms wieder erfolgen.

    Auf diese Weise lässt sich schon das ein oder andere Mal die Eingabe Latenz um ein Bild senken, nicht jedoch die außerhalb des Emulators generierte Eingabe Latenz.


    - Vsync abschalten

    Beim Vsync blockiert die Grafikkarte die Emulation eine gewisse Zeit bis ein neues Bild eingefügt werden kann. In dieser Zeit kann die Eingabe nicht geprüft werden. Natürlich will man auf flüssiges scrolling nicht verzichten.

    Beam Racing beschreibt eine Möglichkeit flüssiges scrolling ohne Vsync zu erreichen. Das ist ein Kapitel für sich und sei deswegen hier nur am Rande bemerkt.

    Eine Rest Latenz bleibt jedoch auch hier zurück.


    - Vsync Verhalten selber programmieren

    Hierbei hat man mehr Kontrolle innerhalb der Wartezeit. Es ist jedoch nicht ganz trivial die gleiche Genauigkeit wie das automatisierte Vsync der Grafikkarte zu erreichen. WinUAE verwendet ein selbst gebautes Low Latency Vsync.

    Eine Rest Latenz bleibt jedoch auch hier zurück.


    - Run Ahead

    diese Technik verursacht eine Zeit Verschiebung in der Emulation und ist um es vorweg zu nehmen in der Lage sämtliche Eingabe Latenz zu eliminieren. Es ist sogar möglich eine niedrigere Latenz als das Original zu erreichen.

    Das hat jedoch einen hohen Preis und der lautet Performance.

    Wie funktioniert das?

    Als erstes muss der Emulator in der Lage sein, Spielstände zu generieren. Nehmen wir an es sollen 2 Bilder Latenz eliminiert werden. Für die Emulation eines jeden Bildes ist dann folgendes zu tun:

    • taste alle Eingabe Geräte ab
    • emuliere ein Bild und verwerfe Video und Audio (nicht durch den Host ausgeben lassen)
    • generiere ein Spielstand im Arbeitsspeicher
    • emuliere ein weiteres Bild und verwerfe ebenso Video und Audio (nicht durch den Host ausgeben lassen)
    • emuliere das letzte Bild aber mit Ausgabe von Video und Audio durch den Host
    • lade den zuvor gesicherten Spielstand wieder

    Es werden in einem emulierten Bild somit 3 Bilder emuliert. Das erklärt warum die Performance so stark beansprucht wird.

    Der Emulator läuft 2 Bilder in der Vergangenheit, das heißt die aktuelle Eingabe wird in dem Zustand des Emulators vor 2 Bildern verarbeitet. Die ersten beiden Bilder werden versteckt emuliert und erst das 3. Bild kommt zur Anzeige.

    Wir sehen nun das Resultat, als hätten wir die Eingabe 2 Bilder vor dem Aktuellen getätigt. Damit simulieren wir die schnelle Verarbeitung, welche das Original Gerät nur benötigt um die Eingabe zu registrieren.

    Abschließend wird der Spielstand, welcher nach dem ersten Bild gezogen wurde, wieder geladen damit der Emulator in einem Bild tatsächlich auch nur ein Bild vorankommt, ansonsten wären ja 3 Bilder vergangen.

    Intern ist der Emulator also im gleichen Zustand, wie normal auch. Audio und Video Verzerrungen sind komplett ausgeschlossen. Es wird nur das Audio und Video des letzten Bildes an den Host übertragen.

    Ein Bild zu eliminieren ist eine sichere Angelegenheit um bei keinem Spiel tiefer als das Original zu kommen, also die natürliche Latenz zu eliminieren. Alles darüber hinaus muss ausprobiert werden. Geht man zu tief verwirrt man die Spiellogik.

    Auch bemerkt man es durch Bild (verpasst erste Sprung Animation ) oder Ton (z.B. Sprunggeräusche der Spielfigur spielen nicht von vorne)

    Aus dem Grund wird die Anzahl der eliminierten Bilder am Besten über Hotkeys zur Laufzeit gesteuert.

  • - Run Ahead

    diese Technik verursacht eine Zeit Verschiebung in der Emulation und ist um es vorweg zu nehmen in der Lage sämtliche Eingabe Latenz zu eliminieren.

    Zu dieser Technik findet sich z.B. hier ein englischsprachiger Artikel, der auch die Bilderabfolge gut darstellt:


    Run-Ahead for Input Latency Reduction

  • Eine eventuell kommende "Run Ahead" Funktion im Denise könnte man dann ja als einschaltbare oder ausschaltbare Option gestalten, oder? Ich frage für diejenigen User, deren Rechner dann vielleicht keinen Fullspeed ohne Frameskipping mehr schaffen würde. Ob meiner dies dann schafft, werde ich ja sehen. Aber diese Funktion wird dann, falls sie kommt, notfalls auch abschaltbar sein, sodaß sie dann die CPU des PC's nicht mehr als bisher belastet, nehme ich an?

  • Mir kommt Run-Ahead fast vor wie Zeitreisen. Wenn man es mal hinbekommt, dass die Spielfigur springt, BEVOR ich überhaupt den Button gedrückt habe, dann würde ich so manches Spiel besser schaffen. ;)


    (obwohl ich ja neben Auto-Fire dank ML (Machine Learning) auch irgendwann auf Auto-Control und Auto-Win hoffen kann). ;)


    Zurück zum Thema ...

  • Ob meiner dies dann schafft, werde ich ja sehen. Aber diese Funktion wird dann, falls sie kommt, notfalls auch abschaltbar sein, sodaß sie dann die CPU des PC's nicht mehr als bisher belastet, nehme ich an?

    ja das ist natürlich komplett optional und initial immer abgeschalten.


    Es gibt Spiele, die nur aller 2 Bilder die Eingabe Geräte abtasten. Da ist dann sogar besonders bitter, wenn die Abtastung verpasst wird. Es kommen dann 40 ms Latenz oben drauf.

  • Hm, hört sich interessant an, aber was ist, wenn der Input in den vorweggenommenen Frames sich signifikant auf das weitere Geschehen auswirkt? Z.B.: ich gehe nach links und es werden 3 Frames vorherberechnet. Irgendeinen Input muss man ja in diesen 3 Frames annehmen, also z.B. dass ich weiter nach links gehe. Jetzt ist da aber ein Gegner und es kommt zum Playertod, und das Spiel fängt an, die Death-Animation abzuspielen. Den ersten Frame davon sehe ich auf dem Bildschirm. Im nächsten Frame lasse ich den Joystick aber los, und verhindere dank meines spitzenmäßigen Reaktionsvermögens die Kollision. Damit hat der Death nie stattgefunden, und es wird ein Frame vorherberechnet, in dem der Spieler überlebt. Das führt ja nun zu einem blöden Glitch in der Darstelliung, richtig?

  • Hm, hört sich interessant an, aber was ist, wenn der Input in den vorweggenommenen Frames sich signifikant auf das weitere Geschehen auswirkt? Z.B.: ich gehe nach links und es werden 3 Frames vorherberechnet. Irgendeinen Input muss man ja in diesen 3 Frames annehmen, also z.B. dass ich weiter nach links gehe. Jetzt ist da aber ein Gegner und es kommt zum Playertod, und das Spiel fängt an, die Death-Animation abzuspielen. Den ersten Frame davon sehe ich auf dem Bildschirm. Im nächsten Frame lasse ich den Joystick aber los, und verhindere dank meines spitzenmäßigen Reaktionsvermögens die Kollision. Damit hat der Death nie stattgefunden, und es wird ein Frame vorherberechnet, in dem der Spieler überlebt. Das führt ja nun zu einem blöden Glitch in der Darstelliung, richtig?

    Die zusätzlichen Frames stellen die Verzögerung (Transportweg) am PC dar, die es auf dem echten C64 nicht gibt. Es ist die Zeit, die zwischen Eingabe und Verarbeitung vergeht. Somit verändert sich in dieser Zeit der ursprüngliche Input nicht.

    Übertrieben gesagt kommt mit dieser Technik die Eingabe, die du für das Frame was du siehst beabsichtigst, auch in diesem Frame an.

    Run Ahead verkürzt den Transportweg nicht. Das würde nur gehen wenn man ein eigenes OS schreibt und ein CRT verwendet... praktisch also nicht möglich

    Da der Transportweg nicht verkürzt werden kann, wird die Eingabe in dem Beispiel um 2 Bilder vor dem eigentlich angezeigten verarbeitet. Wir sehen hier also nicht die entfernte Zukunft, welche wir in der nahen Zukunft ändern könnten.

    Gehen wir aber über diesen Transportweg passiert das was du beschreibst und man verwirrt die Spiellogik.

  • Damit hat der Death nie stattgefunden, und es wird ein Frame vorherberechnet, in dem der Spieler überlebt.

    Um Gottes Willen 8\|. Könnte das gar, unter Annahme des worst case, eine Zeitschleife auslösen, ähnlich wie bei "Und täglich schmerzt mein Mümmel mir", äääääääääääähhhhhhh ich meinte natürlich "Und täglich grüßt das Murmeltier", in der ein Spieler dann auf ewig gefangen sein könnte? :sieroh :emojiSmiley-16: :silly:

  • Wie verhält es sich dann eigentlich bei Save-States im Zusammenhang mit Run-Ahead. Kann dann ein bei "Run Ahead eingeschaltet" erstellter Save-State, danach dann nur wieder verwendet werden, wenn dann ebenfalls wieder "Run Ahead" an ist?

    nein. kann an sein, muss aber nicht. Hier gibt es kein Problem.

  • habe ein nightly fertiggestellt, welches Just in Time Polling verwendet, also noch nicht Run Ahead.

    Erklärung für JIT Polling ist im ersten Posting zu finden.

    Ich persönlich könnte nicht sicher sagen, ob es was gebracht hat oder nicht.


    funktioniert nur, wenn mindestens audio sync aktiv ist und kein analoger Controller im Emulator zugewiesen ist (wie Guns, Pens, Mouse)

  • Quote

    Ich persönlich könnte nicht sicher sagen, ob es was gebracht hat oder nicht.


    Allein wird das auch nicht viel bringen. 5-10ms vielleicht? Das merkt man so noch nicht. Erst ab 30-40ms wird das richtig spürbar. Soviel Gesamt Lag ist auf jedenfall immer vorhanden. Auf vielen Hardware-/Software Konfigurationen sicher noch mehr.

  • Allein wird das auch nicht viel bringen. 5-10ms vielleicht?

    ist stark schwankend. hängt ab davon wann audio sync den Puffer voll hat und den Emulator kurz pausiert damit die Anzahl der Audio Samples pro Sekunde mit dem Echt System übereinstimmt.


    Ansonsten läuft der Emu ja mit max speed, soll heißen wenn die Software auf Zeile 10 pollt heißt das nicht, das auch die Original PAL Zeit von 10 Zeilen vergangen ist. Dazu müsste man jede oder zumindest aller paar Bildzeilen mit der Bildwiederholrate synchronisieren, so wie es beim Beam Racing abläuft (siehe Slices). JIT Polling wird also durch Beam Racing effektiver.


    bestenfalls ein halbes frame (also 10 ms).


    Erst ab 30-40ms wird das richtig spürbar. Soviel externer Lag ist auf jedenfall immer vorhanden. Auf vielen Hardware-/Software Konfigurationen sicher noch mehr.

    ist krass, was ein moderner PC da an LAG verursacht. Ich schätze hier liegt ein großer Vorteil bei FPGA Emulatoren.

  • Ja, FPGA kann ja (wie ich das verstehe) alle Tasks parallel abarbeiten und ein Host OS ist auch nicht vorhanden.


    Vsync abschalten ist bringt natürlich sofort was, aber nur aber G-Sync-/Freesync Geräten sinnvoll. Hattest du die native Windows Version vom aktuellen bsnes eigentlich mal gestestet, mit 2-3 Frames Lag durch Runahead rausgenommen ? Das ist schon ein gewaltiger Unterschied, und steuert sich verdammt präzise und flüssig.

  • Was ich noch erwähnen wollte, der effektive Gewinn von Just in Time Polling schwankt stärker als erwartet. Wenn ein Spiel in einer Zeile die Eingabe abtastet und verpasst, ist es ja nicht so, dass es in einigen Zeilen später neu versucht wird, sondern erst ein komplettes Frame oder auch zwei je nach Spiel später. Ausgehend davon erhöht Just in Time Polling nur die Wahrscheinlichkeit, dass die Eingabe ein Bild eher verarbeitet wird. Es verbessert also nicht fest um x Milisekunden, sondern zufällig um 0 ms oder um 20 ms. Schwankt ständig.

    Hattest du die native Windows Version vom aktuellen bsnes eigentlich mal gestestet, mit 2-3 Frames Lag durch Runahead rausgenommen ? Das ist schon ein gewaltiger Unterschied, und steuert sich verdammt präzise und flüssig

    ne noch nicht, werde ich die Tage mal ausprobieren.

  • Es verbessert also nicht fest um x Milisekunden, sondern zufällig um 0 ms oder um 20 ms. Schwankt ständig.


    Was in Spielen dann aber in Sachen Lenk-Feeling auch verwirrend sein kann, finde ich. Man gewöhnt sich ja an eine gewisse Latenz, solange diese nicht zu hoch und wirklich hinderlich ist (wie etwa bei den alten USB Competitions, da war es unspielbar), nur wenn diese Latenz immer schwankt, dann kann man sich an nichts gewöhnen in dem Fall, was dann auch nicht ideal ist.

  • Was in Spielen dann aber in Sachen Lenk-Feeling auch verwirrend sein kann, finde ich. Man gewöhnt sich ja an eine gewisse Latenz, solange diese nicht zu hoch und wirklich hinderlich ist (wie etwa bei den alten USB Competitions, da war es unspielbar), nur wenn diese Latenz immer schwankt, dann kann man sich an nichts gewöhnen in dem Fall, was dann auch nicht ideal ist.

    Ich "schätze" das Schwanken kommt nur bei Spielen zum Tragen, die nicht immer in der gleichen Bildzeile die Eingabe prüfen. In wie weit das nachher spürbar ist, wenn die Eingabe Verarbeitung um 20 ms schwankt, ist sicherlich sehr subjektiv. Aus diesem Grund wird auch Just in Time Polling ein zuschaltbares Feature sein.

    Das Feature gewinnt an Bedeutung wenn Beam Racing in Denise einzieht, da hierfür eine zeitliche Synchronisation zur PAL Frequenz aller paar Bildzeilen notwendig ist.

    Werden nur komplette Bilder an die Grafikkarte übertragen, ist es nicht notwendig aller paar Bildzeilen zur Original Geschwindigkeit zu synchronisieren sondern spätestens am Ende des Bildes oder wenn der Audio Puffer voll läuft in Hinblick darauf das die richtige Anzahl Samples pro Sekunde spielt.

  • kurzes update.

    Die Ergebnisse sind leider ziemlich ernüchternd.

    Auf meiner CPU ( I5-2500K 4x Core @ 3.3 GHz von 2011) kann ich nur 2 frames input Lag entfernen. Das 2. frame ist jedoch so knapp an der Mindestgeschwindigkeit, dass ich praktisch nur ein frame beruhigend entfernen kann.

    Ich schätze die aktuell schnellste CPU wird bestenfalls 3 Frames packen. 60 ms kompensiertes Input Lag ist für dieses Feature sicherlich ausreichend. Jedoch werden nur wenige die notwendigen Hardware Ressourcen mitbringen.


    Ich habe einige Abläufe optimiert, was in Summe ca. 5 weitere FPS eingebracht hat. Es ist jedoch von meiner Seite nicht vorstellbar, derart zu optimieren das RunAhead weitere komplette Frames Input Latenz kompensieren kann.

    Für dieses Feature müssen Kompromisse her.


    Als erstes habe ich in den nicht sichtbaren frames die Emulation des VIC's auf ein Minimum zurückgefahren. Damit schaffe ich 3 Frames Input Lag zu entfernen. Das merkt man schon sehr deutlich. Ich schätze mehr als 40 ms, also 2 frames, ist Cheaten.

    Der Nachteil dieses Verfahrens ist, das die Kollision Register des VIC's nicht funktionieren. Hierfür ist es notwendig die komplette Grafik Emulation voranzutreiben. Die gute Nachricht ist, das viele Spiele diese gar nicht verwenden.

    Das liegt daran, dass bei der Kollision mehrerer Sprites keine Aussage darüber getroffen werden kann, welche Sprites sich denn nun "genau" berührt haben. Sind z.B. Sprite 1, 2 und 3 in einer Kollision verwickelt, kann man nur sagen Sprite 1 ist mit Sprite 2 und/oder Sprite 3 kollidiert.

    Beim Amiga ist das Verhalten identisch.

    Wenn diese Version rund ist, bereite ich ein nightly vor.


    Danach versuche ich eine weitere Alternative. Die Zyklen exakte Emulation ist für dieses Feature zu teuer. Zyklen exakte Emulatoren gibt es schon seit über 10 Jahren. Jedoch sind die meisten Zyklen exakten Emulatoren nicht vollständig Zyklen exakt. Die Grafikeinheit ist es häufig nicht, sondern generiert eine komplette Bildzeile anstatt diese Pixel für Pixel parallel zum Voranschreiten der anderen Komponenten aufzubauen. Selbst Higan hat erst seit wenigen Jahren eine Zyklen genaue Emulation der Grafikhardware im Programm. Diese steht laut Autor jedoch noch am Anfang. Die C64 Emulation ist hier deutlich weiter.

    Viele Spiele benötigen diese Art der Genauigkeit nicht. Es sind eher die Demos, welche die Grafikhardware innerhalb der aktuell entstehenden Bildzeile manipulieren. Spiele haben für solche Tricks kaum Zeit, da irgendwann die Spiellogik ja auch berechnet werden muss, anstatt ein fester Ablauf von Animationen.

    Die Idee ist es einen optionalen Scanline basierten Renderer anzubieten. Davon würde nicht nur RunAhead profitieren, sondern auch Nutzer langsamerer CPU's.


    Nachtrag: Am Besten ist es per Hotkey den Scanline basierten Renderer zum Zyklen exakten hin und her zuschalten. Auf diese Weise lässt sich schnell checken, was geht und was nicht.

  • Huh? Wo ist da denn ein Problem. Ich habe eine AMD Ryzen 5 3600 CPU, die ist zwar recht gut aber nicht gerade High End. Damit packe ich z.B. locker 4 Frames Input Lag durch Runahead in bsnes zu entfernen. Schätze eine I5-2500 CPU ist da dann wohl schon zu schwachbrüstig. Oder hast du da einfach zu fordernde Abläufe in deinem Emulator? Fordert die 100% cycle exakte Emulation soviel Power in Verbindung mit Runahead? Beam Racing wäre wohl resourcenschonender, wenn man nicht gerade komplexe Shader mit dazu nimmt.


    Naja, wenn Spiele eh nicht die komplett 100% Zyklus exakte Emulation brauchen könnte man die doch nur für Demos zuschaltbar machen. Glaube bei Micro64 ist das so geregelt. Da ist die "Single Pixelclock Emulation" ein/ausschaltbar. Und Demos brauchen dann eh keine Runahead Funktion. Aber wahrscheinlich habe ich das mal wieder falsch verstanden und in Denise existiert derzeit eh nur die volle Pixel für Pixel Methode.