[C++] [D3D9] Input Lag - Framelimit - Energiesparplan

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Benutzeravatar
Goderion
Beiträge: 82
Registriert: 16.09.2012, 12:02

[C++] [D3D9] Input Lag - Framelimit - Energiesparplan

Beitrag von Goderion »

Hallo, ich habe zwei Fragen:

A. Warum reduziert sich bei vielen Spielen der Input Lag, wenn man bei aktivem VSync ein Framelimit etwas unter der eingestellten Hz setzt? Ich habe dieses Phänomen schon mehrmals selbst erlebt und man kann von diesem "Trick" auch oft in Foren lesen. Ich habe aber keine Ahnung, warum das manchmal funktioniert.

B. Zur Erklärung erstmal zwei Bilder:

- Rote Linie = Input Lag (Zeitraum vom Aufbau des Frames inklusive Anzeigen/Present)
- Grüne Linie = Frametimes (protokolliert auf Basis vom Zeitpunkt direkt nach dem IDirect3DDevice9::Present)
- Der Wechsel von Grau zu Weiß zeigt den Punkt, wo die Frametimes optimal wären (16,66 Millisekunden, da 60Hz = 1000 / 60 = 16,66)

1. Windows-Energiesparplan auf Höchstleistung
cpu_max_perf.jpg
2. Windows-Energiesparplan auf Ausbalanciert (Standard)
cpu_normal_perf.jpg
Beim zweiten Bild taktet die CPU immer im unteren Bereich hin und her, da die Anforderungen an die CPU auch immer hin und her schwanken. In der Anwendung wird versucht, den Input Lag zu reduzieren, indem man das nächste Frame erst anfängt zu zeichnen, wenn es wirklich nötig ist.

Beispiel ohne den Versuch, den Input Lag zu reduzieren:
a. Benutzereingaben werden verarbeitet
b. Frame wird gerendert und angezeigt

Beispiel mit dem Versuch, den Input Lag zu reduzieren:
a. Benutzereingaben werden verarbeitet
b. Aufgrund des vorigen Frames wird geguckt, wie viel Zeit noch über ist (Zeit bis zum nächsten Present minus Zeit des Zeichnens vom letzten Frame)
c. Ist noch genug Zeit über, geht es mit Punkt a weiter, sonst geht es zu Punkt d
d. Frame wird gerendert und angezeigt

Wie man sieht, macht einem die automatische Takt-Anpassung der CPU da einen gewaltigen Strich durch die Rechnung. Durch den ständig wechselnden Takt ändern sich auch die Renderzeiten, was eine Vorhersage der kommenden Renderzeiten sehr ungenau macht.

Die Frage ist, was mache ich jetzt? Ich sehe zwei Möglichkeiten:
1. Die Funktion zur Reduktion des Input Lags anpassen, damit diese die Taktänderungen erkennt und entsprechend reagiert (riecht nach viel Aufwand)
2. Dafür sorgen, dass die CPU immer mit dem höchsten Takt läuft

Ich tendiere momentan zu 2. Je schneller ein Frame fertig ist, desto geringer ist der Input Lag. Selbst wenn ich es schaffe, die Frametimes bei wechselndem CPU-Takt zu stabilisieren, wird der Input-Lag aufgrund des Takt-Gehopses hin und her schwanken, was eigentlich auch Mist ist.
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] [D3D9] Input Lag - Framelimit - Energiesparplan

Beitrag von Krishty »

Hast du den CPU-Takt gemessen und weißt, dass er schwankt, oder vermutest du es nur?

Test bitte nochmal mit timeBeginPeriod(1) am Anfang des Programms … oder mit PRESENT_INTERVAL_ONE statt PRESENT_INTERVAL_DEFAULT. Ändert sich was? (Quelle)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Goderion
Beiträge: 82
Registriert: 16.09.2012, 12:02

Re: [C++] [D3D9] Input Lag - Framelimit - Energiesparplan

Beitrag von Goderion »

Krishty hat geschrieben:Hast du den CPU-Takt gemessen und weißt, dass er schwankt, oder vermutest du es nur?
Ich messe den Takt direkt in der Anwendung, mit CPU-Z und mit CoreTemp. Alle drei Messungen zeigen deutlich, dass die CPU hoch -und runtertaktet.
Krishty hat geschrieben:Test bitte nochmal mit timeBeginPeriod(1) am Anfang des Programms … oder mit PRESENT_INTERVAL_ONE statt PRESENT_INTERVAL_DEFAULT. Ändert sich was?
timeBeginPeriod(1) benutze ich bereits, was aber eigentlich überflüssig ist, da anscheinend Direct3D9 dies ebenfalls macht.
PRESENT_INTERVAL_ONE benutze ich auch schon. Ein Test mit PRESENT_INTERVAL_DEFAULT ändert nichts.
Krishty hat geschrieben:(Quelle)
Danke für den Link, werde mir das gleich genau durchlesen.
Benutzeravatar
Goderion
Beiträge: 82
Registriert: 16.09.2012, 12:02

Re: [C++] [D3D9] Input Lag - Framelimit - Energiesparplan

Beitrag von Goderion »

Ich habe mir den Link (http://cbloomrants.blogspot.de/2009/03/ ... -woes.html) durchgelesen, denke aber nicht, dass es mit meinem Problem vergleichbar ist.

Es liegt wohl wirklich am wechselnden Takt der CPU.
Nochmal 2 Bilder zum Vergleich:

1. Windows-Energiesparplan auf Höchstleistung
cpu_max_perf2.jpg
2. Windows-Energiesparplan auf Ausbalanciert (Standard)
cpu_normal_perf2.jpg
Um mögliche andere Faktoren auszuschließen, wurde Multithreading-Rendering und die Input-Lag-Reduzierung bei beiden Messungen/Bilder deaktiviert. Rot und Grün liegen daher sehr nah beieinander.

Die blaue Line zeigt die Zeit, die zum "Sammeln" aller Render-Befehle benötigt wird und die türkise Linie zeigt die Zeit aller Direct3D9-DrawCalls.
Es fehlt noch die Zeit, die die gesammelten Render-Befehle für Direct3D9 vorbereitet, diese ist ungefähr so lang, wie das Sammeln und die DrawCalls zusammen.

Dieses Takt-Rumgehüpfe sorgt also dafür, das manche Frames nicht schnell genug fertig werden, also mehr als 16,66ms brauchen und somit das nächste Present "verpassen"

Das ist doch komplett Banane. Der CPU-Takt pendelt zwischen 800 und 4500 hin und her. (i7 6700K auf 4,5Ghz übertaktet)

Ich habe jetzt etwas eingebaut, das beim Start der Anwendung das Runtertakten der CPU deaktiviert und beim Beenden wieder aktiviert. So ähnlich habe ich das gemacht:

Code: Alles auswählen

PowerGetActiveScheme(NULL, &scheme);
PowerWriteACValueIndex(NULL, scheme, &GUID_PROCESSOR_SETTINGS_SUBGROUP, &GUID_PROCESSOR_IDLE_DISABLE, DISABLED);
PowerSetActiveScheme(NULL, scheme);
Das funktioniert sehr gut, aber eigentlich finde ich das nicht so toll, einfach so im Energiesparplan rumzufummeln. Im schlimmsten Fall kann es passieren, dass das Programm komplett abstürzt und die CPU dann immer mit Maximal-Takt läuft. Nicht wirklich schlimm, aber auch nicht schön. (Betrifft nur die Einstellungen für Netzbetrieb, Einstellungen für den Akkubetrieb fasse ich nicht an.)

Das Problem könnte man vielleicht eleganter lösen, wenn man dafür sorgen könnte, dass die CPU nicht immer so schnell runtertaktet. Mal gucken, vielleicht ist das auch einfach realisierbar.
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] [D3D9] Input Lag - Framelimit - Energiesparplan

Beitrag von Krishty »

Ich wollte nur ausschließen, dass die Timer schuld sind (verhalten sich auf Höchstleistung anders).

Das ist wirklich eine beschissene Situation; mein Beileid. Das mit dem Energiesparplan ist eine globale Lösung für ein lokales Problem, um „nicht so toll“ zu spezifizieren – aber was besseres fällt mir auch nicht ein.

Fang bloß nicht mit Spin Loops oder sowas an – das Problem tritt wahrscheinlich nicht auf älteren CPUs auf (Auslastung höher, takten deshalb nicht runter) und auch nicht auf zukünftigen (Auslastung niedriger, erledigen deine Anwendung komplett auf Minimaltakt), aber genau die würdest du mit Spin Loops zu unrecht treffen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Goderion
Beiträge: 82
Registriert: 16.09.2012, 12:02

Re: [C++] [D3D9] Input Lag - Framelimit - Energiesparplan

Beitrag von Goderion »

Krishty hat geschrieben:Fang bloß nicht mit Spin Loops oder sowas an – ...
Was ist mit Spin Loops gemeint? Eine "sinnlose" Schleife, die dafür sorgt, dass die CPU-Auslastung steigt?
Das würde vermutlich eh nichts bringen, da dies nur zur Takterhöhung des Kernes führen würde, auf dem der Spin Loop/Thread läuft.
Ich weiß nicht, seit wann CPU ihre Kerne unabhängig voneinander takten können, aber meiner kann es, und die meisten neuen/kommenden CPU werden es vermutlich auch können.

So ein Spin Loop wäre auch kontraproduktiv, da ich viel Zeit aufgewendet habe, um die Anwendung so CPU-schonend zu machen, wie es geht. Ich mag keine Anwendungen, die kaum was machen, aber die CPU prügeln, so wie z.B. manche Flash-Games. Billigstes 2D-Klickfest aber ein oder mehrere CPU-Kerne auf 100%... nicht schön!
Krishty hat geschrieben:... das Problem tritt wahrscheinlich nicht auf älteren CPUs auf (Auslastung höher, takten deshalb nicht runter) und auch nicht auf zukünftigen (Auslastung niedriger, erledigen deine Anwendung komplett auf Minimaltakt), aber genau die würdest du mit Spin Loops zu unrecht treffen.
Ich denke das Taktproblem wird leider mit alten und neuen CPU möglich sein, da die CPU-Belastung in der Anwendung variiert und man nur einen bestimmten Last-Bereich erreichen muss, damit die CPU mit dem Takt tanzt. Meiner Meinung nach taktet die CPU in solchen Situationen einfach zu schnell runter, bzw. zu langsam wieder hoch.

-

Normalerweise durchlaufe ich vor dem Present eine Schleife, die solange Sleep(1) aufruft, bis die Zeit zum nächsten Present unter 3ms fällt. Das hatte ich eingebaut, da es auf manchen Computern zu hoher CPU-Last kam, wenn ich direkt ins Present gehe, als wäre dort ein Spin Loop, der permanent die VSync checkt. Die Deaktivierung dieses Wartens ändert auch nichts.

Also selbst wenn ich nirgends Sleep(X) aufrufe, direkt im gleichen Thread alles mache, verpasse ich wegen dem CPU-Taktkäse immer wieder mal das nächste Present.

Die Aussichten auf eine Möglichkeit, die CPU so einzustellen, dass sie langsamer runtertaktet, stehen wohl schlecht. Folgende GUID sind zwar von Microsoft definiert und dokumentiert, aber wenn ich diese benutze (PowerReadACValueIndex/PowerWriteACValueIndex), bekomme ich einen Fehler (2 - Datei nicht gefunden).

Code: Alles auswählen

Guid GUID_PROCESSOR_PERF_DECREASE_TIME(0xd8edeb9b, 0x95cf, 0x4f95, 0xa7, 0x3c, 0xb0, 0x61, 0x97, 0x36, 0x93, 0xc8);
Guid GUID_PROCESSOR_IDLE_TIME_CHECK(0xc4581c31, 0x89ab, 0x4597, 0x8e, 0x2b, 0x9c, 0x9c, 0xab, 0x44, 0xe, 0x6b);
Guid GUID_PROCESSOR_IDLE_DEMOTE_THRESHOLD(0x4b92d758, 0x5a24, 0x4851, 0xa4, 0x70, 0x81, 0x5d, 0x78, 0xae, 0xe1, 0x19);
Guid GUID_PROCESSOR_IDLE_PROMOTE_THRESHOLD(0x7b224883, 0xb3cc, 0x4d79, 0x81, 0x9f, 0x83, 0x74, 0x15, 0x2c, 0xbe, 0x7c);
Guid GUID_PROCESSOR_PERF_DECREASE_THRESHOLD(0x12a0ab44, 0xfe28, 0x4fa9, 0xb3, 0xbd, 0x4b, 0x64, 0xf4, 0x49, 0x60, 0xa6);
Google ist mir auch keine wirkliche Hilfe, bzw. suche ich wohl falsch.
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] [D3D9] Input Lag - Framelimit - Energiesparplan

Beitrag von Krishty »

Goderion hat geschrieben:Ich mag keine Anwendungen, die kaum was machen, aber die CPU prügeln, so wie z.B. manche Flash-Games. Billigstes 2D-Klickfest aber ein oder mehrere CPU-Kerne auf 100%... nicht schön!
Klar, aber wir haben mit solchen Threads einen ganz guten Page Rank, und ich spreche dann immer auch zu anderen, die mal über den Thread stolpern :)
Goderion hat geschrieben:Folgende GUID sind zwar von Microsoft definiert und dokumentiert, aber wenn ich diese benutze (PowerReadACValueIndex/PowerWriteACValueIndex), bekomme ich einen Fehler (2 - Datei nicht gefunden).

Code: Alles auswählen

Guid GUID_PROCESSOR_PERF_DECREASE_TIME(0xd8edeb9b, 0x95cf, 0x4f95, 0xa7, 0x3c, 0xb0, 0x61, 0x97, 0x36, 0x93, 0xc8);
Guid GUID_PROCESSOR_IDLE_TIME_CHECK(0xc4581c31, 0x89ab, 0x4597, 0x8e, 0x2b, 0x9c, 0x9c, 0xab, 0x44, 0xe, 0x6b);
Guid GUID_PROCESSOR_IDLE_DEMOTE_THRESHOLD(0x4b92d758, 0x5a24, 0x4851, 0xa4, 0x70, 0x81, 0x5d, 0x78, 0xae, 0xe1, 0x19);
Guid GUID_PROCESSOR_IDLE_PROMOTE_THRESHOLD(0x7b224883, 0xb3cc, 0x4d79, 0x81, 0x9f, 0x83, 0x74, 0x15, 0x2c, 0xbe, 0x7c);
Guid GUID_PROCESSOR_PERF_DECREASE_THRESHOLD(0x12a0ab44, 0xfe28, 0x4fa9, 0xb3, 0xbd, 0x4b, 0x64, 0xf4, 0x49, 0x60, 0xa6);
Google ist mir auch keine wirkliche Hilfe, bzw. suche ich wohl falsch.
Auf StackOverflow gab es mal so einen ähnlichen Thread: https://stackoverflow.com/questions/145 ... im-monitor … sieht aus, als ob die Werte einfach nicht für die Funktion gemacht wären. Gibt es die vielleicht nochmal mit anderem Präfix? Klingt irgendwas hier sinnvoll?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Goderion
Beiträge: 82
Registriert: 16.09.2012, 12:02

Re: [C++] [D3D9] Input Lag - Framelimit - Energiesparplan

Beitrag von Goderion »

Krishty hat geschrieben:
Goderion hat geschrieben:Ich mag keine Anwendungen, die kaum was machen, aber die CPU prügeln, so wie z.B. manche Flash-Games. Billigstes 2D-Klickfest aber ein oder mehrere CPU-Kerne auf 100%... nicht schön!
Klar, aber wir haben mit solchen Threads einen ganz guten Page Rank, und ich spreche dann immer auch zu anderen, die mal über den Thread stolpern :)
Das verstehe ich nicht. Ich kann meine von dir zitierte Aussage nicht mit deinem Satz verbinden. :?:
Krishty hat geschrieben:Auf StackOverflow gab es mal so einen ähnlichen Thread: https://stackoverflow.com/questions/145 ... im-monitor … sieht aus, als ob die Werte einfach nicht für die Funktion gemacht wären. Gibt es die vielleicht nochmal mit anderem Präfix? Klingt irgendwas hier sinnvoll?
Die Links haben mir zwar nicht direkt geholfen, aber ich habe die Sache deswegen nochmal genau überprüft und festgestellt, dass ich ein Nasenbär bin! Irgendwann habe ich wohl beim Probieren der einzelnen Werte/Guids den falschen Parameter ersetzt, und ab da kam natürlich nur noch Unsinn bei rum.

Die Einstellung GUID_PROCESSOR_PERF_DECREASE_TIME, welche standardmäßig auf 1 steht, sorgt z.B. bei 100 für ein deutlich stabileren CPU-Takt und die Frametime-Messungen sehen von der Kontinuität fast so aus, wie beim maximalen CPU Takt. Der Input Lag ist allerdings erhöht und manchmal läuft es trotzdem nicht rund, daher habe ich mich jetzt doch dafür entschieden, die CPU auf höchstem Takt laufen zu lassen.

Ich deaktiviere aber nicht mehr die komplette CPU-Energiesparfunktionen durch die Einstellung GUID_PROCESSOR_IDLE_DISABLE, sondern kopiere alle CPU-Einstellungen vom Energiesparplan Höchstleistung in den Energiesparplan Ausbalanciert, und beim Beenden werden wieder die vorigen Werte hergestellt. Beim Testen habe ich gemerkt, dass durch die Aktivierung von GUID_PROCESSOR_IDLE_DISABLE, der Stromverbrauch um 40 Watt steigt und meine CPU um 10° wärmer wird, selbst wenn die Anwendung im Menü rumgammelt und keine CPU-Last vorhanden ist. Die CPU-Einstellungen vom Energiesparplan Höchstleistung erhöhen den Stromverbrauch um weniger als 5 Watt und die CPU-Temperatur ändert sich nicht messbar.
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] [D3D9] Input Lag - Framelimit - Energiesparplan

Beitrag von Krishty »

Goderion hat geschrieben:Das verstehe ich nicht. Ich kann meine von dir zitierte Aussage nicht mit deinem Satz verbinden. :?:
Übertragen:
Du: Was soll ich tun?
Ich: Benutz jedenfalls keine Spin Loops!
Du: Würde ich sowieso nicht. Ich hasse Spiele, die CPU-Leistung verschwenden.
Ich: Gut, aber ich sage es auch für alle, die den Thread jetzt oder später mitlesen.
:)

Mir kam übrigens noch eine Idee: Ab Vista konnte man im Multimedia Scheduler Ressourcen reservieren. Da hat z.B. der Media Player eine seine HDD-Bandbreite angemeldet, damit Videos beim Abspielen nicht ruckeln. Ist nur eine wilde Vermutung, aber … kann man da vielleicht neben HDD- und Netzwerkzeit auch CPU-Zeit reservieren?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] [D3D9] Input Lag - Framelimit - Energiesparplan

Beitrag von Krishty »

Ein Nachtrag, worauf man ebenfalls achten sollte: Intel taktet Kerne herunter, sobald AVX oder AVX-512 benutzt werden, damit die Energieaufnahme der CPU nicht abdreht.

https://blog.cloudflare.com/on-the-dang ... y-scaling/
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten