Derzeit profiliere ich mein iOS. Alle Aufrufe von glDrawArrays sind teuer. Hier ist zum Beispiel ein Screenshot des Rendering-Teils eines Partikelsystems:
Wie Sie sehen können, nimmt der glDrawArrays
Aufruf von dieser Methode 39% der CPU-Zeit in Anspruch. Während andere Anrufe mögen glUniform1i
und glBindVertexArrayOES
sehr schnell sind. Warum ist nicht glDrawArrays
so schnell wie die anderen? Beginnen nicht alle diese Methoden mit gl***
kurzen Funktionen, die der Treiberwarteschlange einen Befehl hinzufügen? Warum dauert es glDrawArrays
im Vergleich zu allen anderen gl-Anrufen länger, bis ein Anruf zur Warteschlange hinzugefügt wird?
Ist das normal oder bedeutet das, dass ich etwas falsch mache?
Als Antwort auf Doug : Nein, das hat nicht funktioniert. Der Aufruf von glFinish () hat tatsächlich eine Weile gedauert, aber der glDrawArrays
Aufruf nimmt im Vergleich zu den Statusänderungen (wie) immer noch viel Zeit in Anspruch glBindVertexArrayOES
.
quelle
Antworten:
Die meisten Fahrer arbeiten mit einem Modell für "Lazy State Changes". Dies bedeutet, dass die überwiegende Mehrheit Ihrer gl * -Aufrufe nicht viel mehr tut , als einen Status aufzuzeichnen, einige Parameter zu speichern und dann sofort zurückzukehren. Dies funktioniert einwandfrei, bis ein gl * -Anruf getätigt wird, der tatsächlich etwas mit all diesem Status tun muss (oder der vom Ergebnis eines anderen zuvor getätigten Anrufs abhängt). Zu diesem Zeitpunkt muss der gesamte zuvor gepufferte Status gesammelt und geleert werden, bevor der Anruf getätigt werden kann.
Was Sie also sehen, ist ein völlig normales, wenn auch leicht irreführendes Verhalten: Die für glDrawArrays aufgezeichnete Zeit ist nicht die Zeit, die glDrawArrays allein benötigt , sondern umfasst auch die Zeit für das tatsächliche Festschreiben einer ganzen Reihe früherer GL-Aufrufe.
Es gibt eine Diskussion darüber für D3D , aber das gleiche Grundprinzip gilt für jede moderne Implementierung einer der beiden APIs. Der wichtigste Punkt, den Sie wegnehmen sollten, ist: "Im Allgemeinen wird der Versuch, Ihre GPU durch Timing der CPU zu profilieren, verwirrend und irreführend sein."
quelle
Möglicherweise sehen Sie die Auswirkungen der Warteschlange. Höchstwahrscheinlich blockiert die Befehlswarteschlange bei diesem Aufruf, weil beispielsweise die Warteschlange zu voll ist oder Sie vsync voraus sind. Es ist wahrscheinlich eine Menge Arbeit vor dem Aufruf von glDrawArrays.
Sie können versuchen, ein glFinish direkt vor glDrawArrays zu setzen, um festzustellen, ob es sich um die Befehle in der Warteschlange handelt, die die Zeit in Anspruch nehmen, oder um den Aufruf von glDrawArrays. Wenn die Warteschlangeneffekte Ihr tatsächlicher Leistungsengpass sind, wird glFinish anstelle des unschuldigen Aufrufs von glDrawArrays dafür verantwortlich gemacht.
Andererseits verbraucht glDrawArrays möglicherweise viel CPU. Ich würde das oben Genannte versuchen, um sicherzugehen, dass Sie das Richtige suchen.
EDIT: glFinish, NICHT glFlush
Ich sage nicht, lassen Sie den glFlush CALL dort. Komm schon Leute, glaubst du wirklich, ich sage, lass den glFlush-Anruf dort? Es ist eine Leistungsuntersuchung .
quelle
Die naive Implementierung, bei jedem gl-Aufruf nur in einen Befehlspuffer zu schreiben, macht wenig Sinn, wenn der Treiber möglicherweise Statusänderungen optimieren kann. Daher ist es sinnvoll, die Verarbeitung so spät wie möglich zu verschieben, insbesondere bei einer gekachelten / gruppierten Rendering-Architektur, wie es die meisten OpenGL ES-Implementierungen sind.
Auf einigen Architekturen ist es tatsächlich sinnvoll, eine Shader-Verarbeitung erst bei einem glDrawArrays-Aufruf durchzuführen. (Und ja, sogar Ihre ES1.x-Hardware hat wahrscheinlich irgendeine Form von Shadern unter der Haube).
Das Aufrufen von glFinish / glFlush wie doug65536 schlägt vor, dass dies bei gekachelten / gruppierten Architekturen nicht hilfreich ist, da dies zu einem vollständigen Pipeline-Flush führt, der einen sehr, sehr, sehr hohen Overhead auf solchen hat - was dazu führt, dass alles, was sich bisher in der Warteschlange befand, auf jede Kachel und jedes Forcen gerendert wird eine Auflösung beim nächsten Renderzyklus.
quelle
glFinish()
Anrufs sehe ), was dauert dann so lange für denglDrawArrays
Anruf?