2017-02-15 3 views
1

Ich habe 38 Partikelsysteme mit verschiedenen Shadern, und jedes Partikelsystem kann bis zu 200 Mal an verschiedenen Orten (Emittern) der Welt gerendert werden. Die einzige Sache, die ich jeden Frame aktualisieren muss (Upload zu GPU), ist Emitterpositionen (und möglicherweise einige andere Attribute in einigen Systemen), wenn und nur wenn irgendein Partikelsystem aktiv und sichtbar in dem Sichtstumpf ist.Sollte ich mehrere VBOs mit mehreren glBufferSubData() - Aufrufen oder einen einzelnen VBO mit einem glBufferSubData() - Aufruf aktualisieren?

Soll ich zuteilen und aktualisieren alles wie folgt aus: -Allocate ein einzelnes VBO für jedes Partikel-System, das bis 200 Emittern verarbeiten kann. Aktualisieren Sie für jedes Partikelsystem mit glBufferSubData() 0 bis 200 Emitter pro Frame. Führen Sie einen einzelnen Zeichnungsaufruf für jedes Partikelsystem durch.

Wir müssen 38 glBufferSubData() Aufrufe im Worst-Case-Szenario mit dieser Methode durchführen!

OR, soll ich es tun wie dieser (Geteilt VBO): -Allocate eine sehr große VBO, die auf 38 (Partikelsysteme) verarbeiten können * 200 (Emitter pro Partikel-System). Aktualisieren Sie alle Partikelsysteme mit einem einzigen Aufruf von glBufferSubData(). In diesem Fall müssen wir alle Emitter für jedes Partikelsystem gruppieren, , da jeder Zeichnungsaufruf den Start-Offset für jedes Partikelsystem und seine Emitter kennen muss. Führen Sie einen einzelnen Zeichnungsaufruf für jedes Partikelsystem durch.

Wir müssen glBufferSubData() nur einmal aufrufen!

Es klingt offensichtlich, dass Fall Nr. 2 der Gewinner ist, aber ich habe einige Zweifel. Wir wissen, dass 38 Partikelsysteme einen einzigen VBO teilen, , aber was ist mit dem Stillstand der GPU-Pipeline? Der Grafiktreiber kann nur dann ein VBO-Update durchführen, wenn alle 38 Partikelsysteme mit dem Rendern fertig sind, d. H. Keine Daten vom VBO lesen.

Ich habe Folgendes gefunden: Sie sollten mehrere Pufferobjekte verwenden, um zu verhindern, dass die Rendering-Pipeline während Aktualisierungen des Datenspeichers blockiert wird. Wenn ein Rendering in der Pipeline auf Daten in dem Pufferobjekt Bezug nimmt, das von glBufferSubData aktualisiert wird, insbesondere von dem spezifischen Bereich, der gerade aktualisiert wird, muss dieses Rendering aus der Pipeline ablaufen, bevor der Datenspeicher aktualisiert werden kann.

hier: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBufferSubData.xhtml

Sollte ich verdoppeln oder sogar verdreifachen Pufferung für Fall nr 2?

+0

38 * 200 = 7600 Positionen ist nichts. Die GPU sollte sie kurz blinken lassen. Warum die Mühe? – Ripi2

+0

Jede Emitterposition repräsentiert 150-300 Partikel auf der GPU. Die große Frage ist, wie der CPU-GPU-Transfer behandelt werden sollte und nicht der GPU-Berechnungs-/Rendering-Teil. – karl88

+0

OK. 2 Millionen sind nicht so klein, aber immer noch nicht so groß. Benchmark es. In dem Fall beide Wege sind langsam (für den ersten Weg, zeichne die Hälfte, Upload und zeichne den Rest) Sie lesen Sie besser das Kapitel 28 Asynchron ... bei http://openenginsights.com/ – Ripi2

Antwort

2

Wie viele Optimierungen, wenn es um Grafiken geht, ist es ein Kompromiss. Indem Sie alle Puffer zu einem konsolidieren, reduzieren Sie die Anzahl der Zustandsänderungen, die zum Zeichnen Ihrer Partikelsysteme für den durchschnittlichen Fall erforderlich sind. Aber Sie verpassen dann eine reduzierte Busbandbreite, wenn Sie eine glBufferSubData() überspringen, wenn sich ein System nicht im Frustum befindet.

Ich wäre nicht besorgt, die GPU-Pipeline zu blockieren, wenn der gesamte Puffer mehr als ein paar MB groß wäre (denken Sie an die Größe eines Rahmens oder zwei in einem hochauflösenden Videostream). Das Ändern einer VBO ist eine viel günstigere Statusänderung als das Ändern eines Shaders oder Framebuffers.

Es kommt meistens darauf an, was Sie noch haben: GPU-Verarbeitung/Synchronisationszeit (in Form von Zustandsänderungen) oder PCI-E-Bus-Bandbreite.

+0

Danke für die Beantwortung! Ja, manchmal kann es schwierig sein, zwischen verschiedenen Lösungen zu wählen. Meine Lösung: Verteilen Sie drei große Pufferobjekte mit Round Robin (Vermeiden Sie implizite Synchronisation) und ordnen Sie einen großen Vektor von Floats zu. Dieser Vektor enthält alle Informationen, die in unserem Frustum in diesem Frame zu sehen sind, und dieser Vektor wird durch einen einzigen Aufruf von glBufferSubData() auf die GPU hochgeladen. – karl88

Verwandte Themen