Effiziente und speicherschonende Mesherstellung in OpenGL

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
dronus
Establishment
Beiträge: 114
Registriert: 11.01.2010, 01:53

Effiziente und speicherschonende Mesherstellung in OpenGL

Beitrag von dronus »

Hallo mal wieder,

ich bastel gerade wieder an OpenGL Code, und habe ein Problem: Ich erstelle eine Menge Objekte, die jeweils einige Zeit verwendet werden (zumeist einige Hundert Frames). Die Vertices werden nicht aus Dateien geladen, sondern berechnet. Der Detailgrad ist dabei von der Kameraperspektive abhängig, daher ist die Vertex-Anzahl bis zum erstellen unbekannt. Ich fülle die Daten daher in einen etwas optimierten Container (ähnlich std::vector<float>). Dann werden sie mit glBufferData mit dem Hint GL_DYNAMIC_DRAW, oder wenn ein altes Buffer Object wiederverwendet wird, mit glBufferSubData kopiert.

Ich weiß nicht, wie lange das kopieren dauert, aber im Falle einer GPU ohne dedizierten Speicher kommt es mir sinnlos vor. Außerdem ist es schwierig, die umgeladenen Container immer zeitnah wegzuräumen, wenn ich das mache wird der Heap schön durchgerührt, wenn ich es aber nicht mache, habe ich bei nicht-dediziertem Speicher schnell ein Speicherproblem. In der Tat verbraucht mein Prozess mit einer Intel GPU unter Linux etwas mehr als doppelt so viel physischen Speicher wie es Vertexdaten zum rendern hat, offenbar wird hier der reservierte Grafikspeicher sauber dem Prozess zugehörig angezeigt.

Gibt es eine schlaue Weise, wie man diese Verdoppelung von Speicher und Schreibvorgängen vermeiden kann? Früher war es ja üblich, GL direkt von Array-Pointern zeichnen zu lassen. Würde diese Technik heute noch funktionieren, und bei integrierten GPUs das kopieren vermeiden?
Benutzeravatar
Krishty
Establishment
Beiträge: 8268
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Effiziente und speicherschonende Mesherstellung in OpenG

Beitrag von Krishty »

Geraten: Da die GPU asynchron läuft, würde dieses direkte Zeichnen wohl nur bewirken, dass OpenGL einen Speicherbereich temporär reserviert bis das Zeichnen fertig ist. Dann würde mindestens gleich viel Speicher verbraucht (falls die GPU nur einen Frame hinterher ist; bei mehr entsprechend mehr Speicher), aber noch viel mehr durchgerührt.

Der API-Trend geht gerade wieder hin zur synchronen GPU (Direct3D 12 kann beim Rendern direkt aus dem RAM lesen), in dieser Richtung könnte es was geben. Ich bezweifle aber, dass Intel-GPUs so weit sind.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Schrompf
Moderator
Beiträge: 4884
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Effiziente und speicherschonende Mesherstellung in OpenG

Beitrag von Schrompf »

Es würde wahrscheinlich erstmal reichen, ein paar vorallokierte Buffer für das Zusammenbauen der Meshes zu benutzen. Du brauchst ja genau genommen den Buffer nur, bis Du die Daten fertig hast und mit glSubBufferData (wirklich SUBbufferdata? BufferData ohne Sub wäre besser, glaube ich) hochlädst. Du brauchst also nur soviele temporäre Speicher, wie Du Meshes gleichzeitig *erstellst*, nicht soviele, wie gleichzeitig *darstellst*.

Außerdem: wenn Du nur für Dich selbst programmierst, ist das zwar möglich, aber die meisten Spieler-GPUs da draußen haben immernoch dedizierten Speicher. Selbst alle Laptop-GPUs haben eine gewisse Menge dediziertem Speicher für die wirklich hochbandbreitigen Sachen. Auf Konsolen wären Deine Überlegungen aber angebracht und sind nach meinem Wissen dort auch üblich.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
dronus
Establishment
Beiträge: 114
Registriert: 11.01.2010, 01:53

Re: Effiziente und speicherschonende Mesherstellung in OpenG

Beitrag von dronus »

Ich hab mich halt nur über die Speicherhungrigkeit von meinem Prozess geärgert. Ohne Buffer Objects kann man ja glDrawArrays direkt aus den C arrays / Containern zeichnen lassen. Wenn dir GPU nur ihren eigenen Speicher lesen kann, kann der Treiber es ja immer noch dahin kopieren. Nur er muss eben nicht, falls der Speicher von CPU und GPU lesbar ist. Nur gilt das eben als veraltet, und wird z.B. in OpenGL ES 2.0 nicht mehr unterstützt soweit ich das sehe.

So wie ich Schrompf verstehe, brauche ich meine eigene Kopie der Daten ja nicht länger zu behalten. Das stimmt, nach dem glBufferData kann ich meinen Container aufgeben, bzw. wieder verwenden.

Im Moment habe ich in meinem Code leider nicht so eine einfache Möglichkeit dazu. Die Objekte werden nicht streng nacheinander erstellt, sondern die verschiedenen Container fassen Vertices für einen bestimmten Raumbereich zusammen. Darum kann ich erst nach Abschluss der gesamten Objekterstellung alle Container in Buffer Objects laden. Bei einem schnellen Kameraschwenk kann so im Extremfall die gesamte Szene auf einmal generiert werden. Dann kommt es zu den Speicherproblemen.

Ich hab schon überlegt, die einzelnen Objekte zu zerlegen, und vielleicht alle 1000 Vertices einfach ein Buffer Object zu füllen, und mit einem leeren Container weiter zu sammeln. Dann komm ich mit deutlich kleineren Containern aus, die dann wirklich nur noch sehr temporär benutzt würden. Im Gegenzug erhöht sich die Anzahl der Draw Calls beträchtlich...
dronus
Establishment
Beiträge: 114
Registriert: 11.01.2010, 01:53

Re: Effiziente und speicherschonende Mesherstellung in OpenG

Beitrag von dronus »

dot hat geschrieben:https://www.opengl.org/wiki/Buffer_Obje ... nt_mapping
Ahh, glMapBuffer scheint zu sein wonach ich gesucht habe. Ich werd mich da mal ein bisschen reinlesen, mal sehen ob ich das hinbekomme und ob es was bringt. Danke!
Antworten