[solved] OpenGL: mehrere VBOs effizienter zeichnen?



  • Grüsse,

    ich bin noch recht unerfahren und hoffe, dass meine Frage nicht allzu laienhaft wirkt.

    Da mir die Funktion gluSphere(GLUquadrics, radius, slices, stacks) zu wenige Möglichkeiten bietet die Kugel ggf. manipulieren zu können (beispielsweise soll auf Wunsch nur jeder 2. stack gezeichnet werden können etc.) und auch die glutSolidSphere-Funktion von glut recht bescheiden ist habe ich mir eine eigene Klasse geschrieben, die eben diese Funktionalitäten zur Verfügung stellt (bzw bin noch dabei).
    Das ist auch nicht allzu problematisch, alle Koordinaten werden bei der Instanziierung berechnet, Normalen werden berechnet etc. etc.

    -Anfangs hab ich in einer zeichen-Methode dann in Schleifen die Vertices angegeben - war zu langsam.
    -Zweiter versuch war dann über VertexArrays zu zeichnen - das war schon wesentlich besser und erreichte fast die Performance der durch GLU oder GLUT zur Verfügung gestellten Funktionen (für eine Kugel mit 100 stacks und 100 slices ca. 700Microsekunden).

    -Dritter und momentaner Ansatz ist über VBOs zu rendern, was natürlich einen enormen Performancesprung brauchte. Dauer für die gleiche Kugel nur noch ca. 7Microsekunden. Also schon recht flott.

    Ich bin mir jetzt nicht sicher, ob ich da noch etwas optimieren kann, so wie beispielsweise glMultiDrawArrays statt mehrmaligen glDrawArrays (wobei ich das irgendwie nicht verstanden hatte - klappte bei mir nicht).

    Momentan wird sowohl für den oberen und untereren stack der Kugel (werden jeweils als GL_TRIANGLE_FAN gezeichnet) ein buffer gefüllt, und für jeden dazwischenliegenden stack (jeder als GL_QUAD_STRIPS gezeichnet) ebenfalls einer.
    Bei einer Kugel mit 100 Stacks fordere ich also über glGenBuffer 200 Buffer an (pro stack 2 stück - einen für Normalen und einen für die Vertices), lade dann die Daten rein usw.
    Dies geschieht natürlich alles nur einmal.

    In der Zeichenmethode binde ich dann pro Stack einen buffer für die Normalen und einen für die Vertices, setze VertexPointer und NormalPointer und zeichne dann per glDrawArrays.
    Das mache ich dann für alle 100 Stacks.

    Die Frage ist nun, ob man das auch eleganter bzw effizienter lösen kann. Eine Möglichkeit wäre sicher InterleavedArrays zu verwenden (noch nicht probiert), aber ich denke dass dadurch kein grosser Performancegewinn zu erwarten ist. Die Daten werden nicht mehr geändert, sodass einmal übertragene Daten (mittels GL_STATIC_DRAW) - ob nun mit vielen arrays oder weniger interleavedArrays - keinen Unterschied machen sollten.
    Vielmehr könnte es ja sein, dass man statt 100 mal glDrawArrays für die VBO aufzurufen irgendeine effizientere Methode finden könnte?

    Gruss,
    Carsten



  • Ich hab die Klasse nun erstmal so umgeschrieben, dass alle Vertex-Daten in ein VBO geschrieben werden und die dann über ein TRIANGLE_STRIP gezeichnet werden, und ale Normalen-Daten in ein zweites VBO.

    Werde die später noch umschreiben, dass komplett alle Daten in nur noch einem VBO landen und ich über einen Element-Buffer auf die Werte zugreife.

    Performance ist recht ansehnlich momentan und ich denke dass ich dort nicht mehr allzuviel optimieren brauch.

    ---------------------

    Was mich allerdings stutzig macht ist, dass das komplette Abarbeiten der Render-Funktion bei 2000 stacks und 2000 slices (pi mal daumen also 8Millionen Triangles) nur ca. 4 Microsekunden dauert, der Aufruf des darauf folgenden SwapBuffers(hDC) (aktiviertes double-buffering) aber geschlagene 25Millisekunden - und damit der grösste Flaschenhals ist.
    Ob es sinnvoll ist Kugeln mit sovielen stacks und slices zu zeichnen sei mal dahingestellt - mache ich ja auch nur um die Performance zu testen.

    Woran könnte es denn liegen, dass ein einfacher swap solange dauert?
    Gibts diesbezüglich Optimierungspotential?

    NACHTRAG:
    Nachdem ich nun am Ende der Rendermethode ein glFinish() gesetzt habe stellt sich die Situation anders dar. Nun benötigt die Rendermeth. 25ms und das swappen nur noch 25microsekunden.
    Mir war nicht klar, dass nach Aufruf von SwapBuffers noch gerendert wird, und somit ggf. gewartet werden muss. Ich dachte, dass die Szene dann schon fertig im Framebuffer läge.

    Also ist der Flaschenhals nur noch die Grafikkarte - Problem also gelöst 🙂



  • Die CPU und die GPU (Grafikkarte) arbeiten Nebeneinander her. In etwa so wie Multiprozessoren.
    Die OpenGL Befehle sagen der Grafikkarte nur: "Mach dies und dass", warten jedoch nicht darauf, dass diese Aufgaben abgeschlossen werden.

    Wenn du nun SwapBuffers aufrufst. Wird darauf gewarted dass die Grafikkarte all ihre Aufträge abgeschlossen hat um dann das Endergebniss anzeigen zu lassen.

    Die 25 Millisekunden sind also die Zeit, die von der Grafikkarte für das Rendern UND dass anschließende Kopieren des Buffers benötigt werden.


Anmelden zum Antworten