Ich habe Probleme, den praktischen Unterschied zwischen Anrufen glFlush()
und zu unterscheiden glFinish()
.
Die Dokumente sagen dies glFlush()
und glFinish()
werden alle gepufferten Operationen an OpenGL senden, so dass man sicher sein kann, dass sie alle ausgeführt werden. Der Unterschied besteht darin, dass sie glFlush()
sofort als glFinish()
Blöcke zurückgegeben werden, bis alle Operationen abgeschlossen sind.
Nachdem ich die Definitionen gelesen hatte, stellte ich fest, dass ich bei Verwendung glFlush()
wahrscheinlich auf das Problem stoßen würde, mehr Operationen an OpenGL zu senden, als ausgeführt werden könnten. Also, nur um es zu versuchen, tauschte ich meine glFinish()
gegen a glFlush()
und siehe da, mein Programm lief (soweit ich das beurteilen konnte), genau das gleiche; Bildraten, Ressourcennutzung, alles war gleich.
Ich frage mich also, ob es einen großen Unterschied zwischen den beiden Aufrufen gibt oder ob mein Code sie nicht anders laufen lässt. Oder wo einer gegen den anderen verwendet werden sollte. Ich dachte mir auch, dass OpenGL einen Aufruf haben würde, um glIsDone()
zu überprüfen, ob alle gepufferten Befehle für a glFlush()
vollständig sind oder nicht (so sendet man Operationen nicht schneller an OpenGL, als sie ausgeführt werden können), aber ich konnte keine solche Funktion finden .
Mein Code ist die typische Spielschleife:
while (running) {
process_stuff();
render_stuff();
}
Wie die anderen Antworten angedeutet haben, gibt es wirklich keine gute Antwort gemäß der Spezifikation. Die allgemeine Absicht von
glFlush()
ist, dass die Host-CPU nach dem Aufruf keine OpenGL-bezogene Arbeit zu erledigen hat - die Befehle wurden auf die Grafikhardware übertragen. Die allgemeine Absicht vonglFinish()
ist, dass nach der Rückkehr keine verbleibende Arbeit mehr übrig bleibt und die Ergebnisse auch für alle geeigneten Nicht-OpenGL-APIs verfügbar sein sollten (z. B. Lesevorgänge aus dem Framebuffer, Screenshots usw.). Ob das wirklich passiert, hängt vom Fahrer ab. Die Spezifikation erlaubt eine Menge Spielraum, was legal ist.quelle
Ich war auch immer verwirrt über diese beiden Befehle, aber dieses Bild machte mir alles klar: Anscheinend senden einige GPU-Treiber die ausgegebenen Befehle nicht an die Hardware, es sei denn, eine bestimmte Anzahl von Befehlen wurde gesammelt. In diesem Beispiel ist diese Zahl 5 .
Das Bild zeigt verschiedene OpenGL-Befehle (A, B, C, D, E ...), die ausgegeben wurden. Wie wir oben sehen können, werden die Befehle noch nicht ausgegeben, da die Warteschlange noch nicht voll ist.
In der Mitte sehen wir, wie sich dies
glFlush()
auf die Befehle in der Warteschlange auswirkt. Der Treiber wird angewiesen, alle Befehle in der Warteschlange an die Hardware zu senden (auch wenn die Warteschlange noch nicht voll ist). Dies blockiert den aufrufenden Thread nicht. Es signalisiert dem Treiber lediglich, dass wir möglicherweise keine zusätzlichen Befehle senden. Daher wäre es Zeitverschwendung, darauf zu warten, dass sich die Warteschlange füllt.Unten sehen wir ein Beispiel mit
glFinish()
. Es macht fast das Gleiche wieglFlush()
, außer dass der aufrufende Thread warten muss, bis alle Befehle von der Hardware verarbeitet wurden.Bild aus dem Buch "Advanced Graphics Programming Using OpenGL".
quelle
glFlush
undglFinish
tue, und ich kann nicht sagen, was dieses Bild sagt. Was ist auf der linken und der rechten Seite? Wurde das Bild auch gemeinfrei oder unter einer Lizenz veröffentlicht, mit der Sie es im Internet veröffentlichen können?Wenn Sie keinen Leistungsunterschied festgestellt haben, bedeutet dies, dass Sie etwas falsch machen. Wie einige andere bereits erwähnt haben, müssen Sie auch nicht anrufen. Wenn Sie jedoch glFinish aufrufen, verlieren Sie automatisch die Parallelität, die GPU und CPU erreichen können. Lass mich tiefer tauchen:
In der Praxis werden alle Arbeiten, die Sie an den Treiber senden, gestapelt und möglicherweise viel später (z. B. zur SwapBuffer-Zeit) an die Hardware gesendet.
Wenn Sie also glFinish aufrufen, zwingen Sie den Treiber im Wesentlichen, die Befehle an die GPU zu senden (die bis dahin gestapelt wurde und die GPU nie zur Bearbeitung aufgefordert hat) und die CPU anzuhalten, bis die übertragenen Befehle vollständig sind hingerichtet. Während der gesamten Zeit, in der die GPU arbeitet, funktioniert die CPU nicht (zumindest in diesem Thread). Und während die CPU ihre Arbeit erledigt (meistens Batching-Befehle), macht die GPU nichts. Also ja, glFinish sollte Ihre Leistung beeinträchtigen. (Dies ist eine Annäherung, da Treiber möglicherweise die GPU bei einigen Befehlen arbeiten lassen, wenn viele von ihnen bereits gestapelt wurden. Dies ist jedoch nicht typisch, da die Befehlspuffer in der Regel groß genug sind, um viele Befehle aufzunehmen.)
Warum sollten Sie dann überhaupt glFinish nennen? Ich habe es nur benutzt, wenn ich Treiberfehler hatte. Wenn einer der Befehle, die Sie an die Hardware senden, die GPU zum Absturz bringt, können Sie am einfachsten nach jedem Draw glFinish aufrufen, um festzustellen, welcher Befehl der Schuldige ist. Auf diese Weise können Sie eingrenzen, was genau den Absturz auslöst
Nebenbei bemerkt, APIs wie Direct3D unterstützen überhaupt kein Finish-Konzept.
quelle
glFlush geht wirklich auf ein Client-Server-Modell zurück. Sie senden alle gl-Befehle über eine Pipe an einen gl-Server. Diese Pipe könnte puffern. Genau wie jede Datei oder Netzwerk-E / A puffern könnte. glFlush sagt nur "Sende den Puffer jetzt, auch wenn er noch nicht voll ist!". Auf einem lokalen System wird dies fast nie benötigt, da sich eine lokale OpenGL-API wahrscheinlich nicht selbst puffert und nur Befehle direkt ausgibt. Außerdem führen alle Befehle, die das tatsächliche Rendern verursachen, eine implizite Leerung durch.
glFinish hingegen wurde zur Leistungsmessung entwickelt. Eine Art PING an den GL-Server. Es löst einen Befehl aus und wartet, bis der Server mit "Ich bin inaktiv" antwortet.
Heutzutage haben moderne, lokale Fahrer ziemlich kreative Ideen, was es bedeutet, untätig zu sein. Ist es "alle Pixel werden gezeichnet" oder "meine Befehlswarteschlange hat Platz"? Auch weil viele alte Programme glFlush und glFinish ohne Grund als Voodoo-Codierung in ihren Code gestreut haben, ignorieren viele moderne Treiber sie einfach als "Optimierung". Ich kann sie nicht wirklich dafür verantwortlich machen.
Zusammenfassend: Behandeln Sie sowohl glFinish als auch glFlush in der Praxis als keine Operationen, es sei denn, Sie codieren für einen alten Remote-SGI-OpenGL-Server.
quelle
Schauen Sie hier . Kurz gesagt heißt es:
Ein anderer Artikel beschreibt andere Unterschiede:
glFlush
glFinish
zwingt OpenGL, ausstehende Befehle auszuführen, was eine schlechte Idee ist (z. B. mit VSync)Zusammenfassend bedeutet dies, dass Sie diese Funktionen nicht einmal benötigen, wenn Sie die doppelte Pufferung verwenden, es sei denn, Ihre Swap-Puffer-Implementierung löscht die Befehle nicht automatisch.
quelle
Es scheint keine Möglichkeit zu geben, den Status des Puffers abzufragen. Es gibt diese Apple-Erweiterung, die den gleichen Zweck erfüllen könnte, aber sie scheint nicht plattformübergreifend zu sein (habe sie noch nicht ausprobiert). Auf den ersten Blick scheint es
flush
, als würden Sie den Zaunbefehl eingeben. Sie können dann den Status dieses Zauns abfragen, während er sich durch den Puffer bewegt.Ich frage mich, ob Sie
flush
vor dem Puffern von Befehlen, aber vor dem Rendern des nächsten von Ihnen aufgerufenen Frames verwenden könntenfinish
. Auf diese Weise können Sie mit der Verarbeitung des nächsten Frames beginnen, während die GPU funktioniert. Wenn dies jedoch bis zu Ihrer Rückkehr nicht erfolgt,finish
wird blockiert, um sicherzustellen, dass sich alles in einem neuen Zustand befindet.Ich habe es nicht versucht, werde es aber in Kürze tun.Ich habe es mit einer alten Anwendung versucht, die eine ziemlich gleichmäßige CPU- und GPU-Nutzung hat. (Es wurde ursprünglich verwendet
finish
.)Als ich es
flush
am Ende undfinish
am Anfang änderte , gab es keine unmittelbaren Probleme. (Alles sah gut aus!) Die Reaktionsfähigkeit des Programms nahm zu, wahrscheinlich weil die CPU nicht auf die GPU wartete. Auf jeden Fall eine bessere Methode.Zum Vergleich entfernte ich mich
finished
vom Anfang des Rahmens und gingflush
, und es hat dasselbe ausgeführt.Ich würde also use
flush
und sagenfinish
, denn wenn der Puffer beim Aufruf von leer istfinish
, gibt es keinen Leistungseinbruch. Und ich vermute, wenn der Puffer voll wäre, sollten Sie esfinish
trotzdem wollen .quelle
Die Frage ist: Möchten Sie, dass Ihr Code weiterhin ausgeführt wird, während die OpenGL-Befehle ausgeführt werden, oder erst, nachdem Ihre OpenGL-Befehle ausgeführt wurden?
Dies kann in Fällen wie bei Netzwerkverzögerungen von Bedeutung sein, wenn eine bestimmte Konsolenausgabe erst nach dem Zeichnen der Bilder oder dergleichen erfolgt.
quelle