Performance: Unterschied zwischen den Versionen

Aus DGL Wiki
Wechseln zu: Navigation, Suche
Zeile 1: Zeile 1:
 
{{Offline}}
 
{{Offline}}
  
=== Einstieg ===
+
__TOC__
 +
 
 +
Dieser Artikel liefert einige Tipps dazu wie man eine OpenGL-Anwendung optimieren kann. Einige der hier genannten Tipps schließen sich gegenseitig aus. Welche Vorgehensweise die beste ist hängt immer davon ab wo gerade der Engpass liegt. Es bringt zum Beispiel wenig den Shader zu optimieren, wenn eigentlich die zu langsame CPU das Problem ist.
 +
 
 +
=== Grundlagen ===
 
# Vermeide Kommunikation zwischen CPU und GPU.
 
# Vermeide Kommunikation zwischen CPU und GPU.
 
#* Lade nicht deine Texturen/Vertexdaten in jedem Frame neu auf die Grafikkarte hoch. Vermeide den Immediate Mode, also [[glBegin]]() und [[glEnd]](). Sofern du aber nur ein, zwei einzelne Dreiecke rendern möchtest ist der Immediate Mode akzeptabel.
 
#* Lade nicht deine Texturen/Vertexdaten in jedem Frame neu auf die Grafikkarte hoch. Vermeide den Immediate Mode, also [[glBegin]]() und [[glEnd]](). Sofern du aber nur ein, zwei einzelne Dreiecke rendern möchtest ist der Immediate Mode akzeptabel.
Zeile 12: Zeile 16:
 
#* Sofern du aufwendige Shader oder viele Texturen verwendest, rendere deine Objekte (nicht Polygone) von vorne nach hinten. Also grob sortieren und den Rest den Z-Buffer machen lassen.
 
#* Sofern du aufwendige Shader oder viele Texturen verwendest, rendere deine Objekte (nicht Polygone) von vorne nach hinten. Also grob sortieren und den Rest den Z-Buffer machen lassen.
 
#* Wenn du transparente Objekte hast, rendere zunächst von die undurchsichtigen Objekte. Die transparenten Objekte renderst du dann sortiert von hinten nach vorne.
 
#* Wenn du transparente Objekte hast, rendere zunächst von die undurchsichtigen Objekte. Die transparenten Objekte renderst du dann sortiert von hinten nach vorne.
# Ein glDraw*** wird nicht sofort ausgeführt, d.h. die CPU erhält die Kontrolle zurück bevor die GPU fertig mit rendern ist. Erst beim SwapBuffers wird synchronisiert. Folglich gebe zuerst der Grafikkarte was zu arbeiten, rechne dann deine Spiellogik, Physik, etc. auf der CPU und rufe dann erst swapBuffers auf. Sowas geht natürlich nicht immer, aber man kann beispielsweise Physik und Rendern in zwei Frames aufspilten. Also du berechnest immer die Physik für das nächste Frame, während die GraKa das aktuelle Frame rendert.
+
# Verwende wenn möglich eine sinnvolle Zeichenreihenfolge. Vermeide häufige Shader/Textur/Material/Statewechsel.
  
 
=== Fortgeschrittene Techniken ===
 
=== Fortgeschrittene Techniken ===
 +
# Ein glDraw*** wird nicht sofort ausgeführt, d.h. die CPU erhält die Kontrolle zurück bevor die GPU fertig mit rendern ist. Erst beim SwapBuffers wird synchronisiert. Folglich gebe zuerst der Grafikkarte was zu arbeiten, rechne dann deine Spiellogik, Physik, etc. auf der CPU und rufe dann erst swapBuffers auf. Sowas geht natürlich nicht immer, aber man kann beispielsweise Physik und Rendern in zwei Frames aufspilten. Also du berechnest immer die Physik für das nächste Frame, während die GraKa das aktuelle Frame rendert.
 +
# Überlege ob du Grafikspeicher sparen kannst indem du z.B. Texturkoordinaten oder Normalen zur Laufzeit im [[Shader]] berechnest.<br>(Beispiel: [[Shader#Beispiel:_Heightmap-Terrain|Heightmap-Terrain]])
 
# Wenn du viele identische Objekte renderst, überlege ob du [[GL_ARB_draw_instanced|Instancing]] einsetzen kannst. Erfordert allerdings halbwegs aktuelle Grafikhardware.
 
# Wenn du viele identische Objekte renderst, überlege ob du [[GL_ARB_draw_instanced|Instancing]] einsetzen kannst. Erfordert allerdings halbwegs aktuelle Grafikhardware.
# Überlege ob du Grafikspeicher sparen kannst indem du z.B. Texturkoordinaten oder Normalen zur Laufzeit im Shader berechnest.<br>(Beispiel: [[Shader#Beispiel:_Heightmap-Terrain|Heightmap-Terrain]])
+
# Verzichte auf einen [[Shader|Geometryshader]], wenn du ihn nicht unbedingt benötigst.
# Vermeide aufwendige Berechnungen im Shader. Möglicherweise ist es sinnvoll komplexe Berechnungen im voraus zu berechnen und im Shader eine Lookup-Textur zu verwenden. Siehe vorheriger auch Tipp. Was sinnvoll ist hängt davon ab, ob eher Rechenleistung oder Speicher(-bandbreite) knapp sind.
+
 
 +
=== Shader ===
 +
# Vermeide aufwendige Berechnungen im Shader. Möglicherweise ist es sinnvoll komplexe Berechnungen im voraus zu berechnen und im Shader eine Lookup-Textur zu verwenden.  
 +
# Verwende nach Möglichkeit die in GLSL integrierten Funktionen. Diese Funktionen können zum Teil wesentlich schneller sein da sie zum Teil direkt in der Hardware implementiert sind.
 +
# Optimiere deine Shader so weit wie möglich. Versuche insbesondere aufwendige Operationen wie zum Beispiel eine Wurzel zu vermeiden. Bedenke das sich solche Operationen auch in eingebauten Funktionen wie beispielsweise {{INLINE_CODE|length}}, {{INLINE_CODE|distance}} und {{INLINE_CODE|normalize}} verstecken können.
 +
# Vermeide Random-Access in Texturen. Zwei nebeneinander liegende Texel einer Textur können üblicherweise schneller aus dem Speicher geladen werden als zwei Texel an völlig unterschiedlichen Positionen in der Textur. Nutze den GPU-Cache!
 +
# Versuche nicht Speicher zu sparen in dem du Variablen im Shader zusammenfasst. Beispielsweise macht eine Variable {{INLINE_CODE|vec4 positionAndSize}} wenig Sinn, wenn Position und Größe nur wenig miteinander zu tun haben und du z.B. ständig mit {{INLINE_CODE|positionAndSize.xyz}} arbeitest. Verwende lieber separate Variablen, also {{INLINE_CODE|vec3 position}} und {{INLINE_CODE|float size}}.<br>Dies gilt nur für lokale Variablen im Shader. Wenn du mit dieser Methode Werte in einer Textur zusammenfassen kannst ist dies natürlich sehr sinnvoll!
 
# Überlege ob du aufwendige Berechnungen, z.B. ein [[GLSL_Partikel_2|Partikelsystem]], nicht besser vollständig auf der Grafikkarte realisierst. Stichworte: [[Tutorial_Framebufferobject|Framebuffer-Objects]] und [[Shader#Transform-Feedback_(auch_Stream-Out)|Transform-Feedback]].
 
# Überlege ob du aufwendige Berechnungen, z.B. ein [[GLSL_Partikel_2|Partikelsystem]], nicht besser vollständig auf der Grafikkarte realisierst. Stichworte: [[Tutorial_Framebufferobject|Framebuffer-Objects]] und [[Shader#Transform-Feedback_(auch_Stream-Out)|Transform-Feedback]].
  
 
=== Quellen ===
 
=== Quellen ===
 
* [http://developer.nvidia.com/object/gpu_programming_guide.html NVIDIA GPU Programming Guide]
 
* [http://developer.nvidia.com/object/gpu_programming_guide.html NVIDIA GPU Programming Guide]

Version vom 2. April 2009, 13:00 Uhr

Hinweis: Dieser Artikel wird gerade Offline bearbeitet!

Bitte haben Sie etwas Geduld und nehmen Sie keine Änderungen vor, bis der Artikel hochgeladen wurde.

(weitere Artikel)
WIP Offline.jpg

Dieser Artikel liefert einige Tipps dazu wie man eine OpenGL-Anwendung optimieren kann. Einige der hier genannten Tipps schließen sich gegenseitig aus. Welche Vorgehensweise die beste ist hängt immer davon ab wo gerade der Engpass liegt. Es bringt zum Beispiel wenig den Shader zu optimieren, wenn eigentlich die zu langsame CPU das Problem ist.

Grundlagen

  1. Vermeide Kommunikation zwischen CPU und GPU.
    • Lade nicht deine Texturen/Vertexdaten in jedem Frame neu auf die Grafikkarte hoch. Vermeide den Immediate Mode, also glBegin() und glEnd(). Sofern du aber nur ein, zwei einzelne Dreiecke rendern möchtest ist der Immediate Mode akzeptabel.
    • Verwende Vertexbuffer-Objects oder Displaylisten.
  2. Verwende glDraw***-Aufrufe sparsam. Hiermit sind ALLE Befehle gemeint die irgendetwas rendern, z.B. glDrawArrays, glDrawElements, ..., aber auch glMultiDrawArrays, usw...
    • Lieber ein paar Polygone mehr rendern, wenn du dadurch glDraw***-Aufrufe einsparen kannst.
    • Es spielt so gut wie keine Rolle, ob du 500 oder 1 Polygon renderst, da ein glDraw***-Aufrufe alleine schon ziemlich viel Zeit braucht.
  3. Nutze den Z-Buffer aus.
    • Sortiere nicht deine Polygone einzeln nach der Entfernung zur Kamera (Painters-Algorithm), sondern verwende den Z-Buffer.
    • Sofern du aufwendige Shader oder viele Texturen verwendest, rendere deine Objekte (nicht Polygone) von vorne nach hinten. Also grob sortieren und den Rest den Z-Buffer machen lassen.
    • Wenn du transparente Objekte hast, rendere zunächst von die undurchsichtigen Objekte. Die transparenten Objekte renderst du dann sortiert von hinten nach vorne.
  4. Verwende wenn möglich eine sinnvolle Zeichenreihenfolge. Vermeide häufige Shader/Textur/Material/Statewechsel.

Fortgeschrittene Techniken

  1. Ein glDraw*** wird nicht sofort ausgeführt, d.h. die CPU erhält die Kontrolle zurück bevor die GPU fertig mit rendern ist. Erst beim SwapBuffers wird synchronisiert. Folglich gebe zuerst der Grafikkarte was zu arbeiten, rechne dann deine Spiellogik, Physik, etc. auf der CPU und rufe dann erst swapBuffers auf. Sowas geht natürlich nicht immer, aber man kann beispielsweise Physik und Rendern in zwei Frames aufspilten. Also du berechnest immer die Physik für das nächste Frame, während die GraKa das aktuelle Frame rendert.
  2. Überlege ob du Grafikspeicher sparen kannst indem du z.B. Texturkoordinaten oder Normalen zur Laufzeit im Shader berechnest.
    (Beispiel: Heightmap-Terrain)
  3. Wenn du viele identische Objekte renderst, überlege ob du Instancing einsetzen kannst. Erfordert allerdings halbwegs aktuelle Grafikhardware.
  4. Verzichte auf einen Geometryshader, wenn du ihn nicht unbedingt benötigst.

Shader

  1. Vermeide aufwendige Berechnungen im Shader. Möglicherweise ist es sinnvoll komplexe Berechnungen im voraus zu berechnen und im Shader eine Lookup-Textur zu verwenden.
  2. Verwende nach Möglichkeit die in GLSL integrierten Funktionen. Diese Funktionen können zum Teil wesentlich schneller sein da sie zum Teil direkt in der Hardware implementiert sind.
  3. Optimiere deine Shader so weit wie möglich. Versuche insbesondere aufwendige Operationen wie zum Beispiel eine Wurzel zu vermeiden. Bedenke das sich solche Operationen auch in eingebauten Funktionen wie beispielsweise length, distance und normalize verstecken können.
  4. Vermeide Random-Access in Texturen. Zwei nebeneinander liegende Texel einer Textur können üblicherweise schneller aus dem Speicher geladen werden als zwei Texel an völlig unterschiedlichen Positionen in der Textur. Nutze den GPU-Cache!
  5. Versuche nicht Speicher zu sparen in dem du Variablen im Shader zusammenfasst. Beispielsweise macht eine Variable vec4 positionAndSize wenig Sinn, wenn Position und Größe nur wenig miteinander zu tun haben und du z.B. ständig mit positionAndSize.xyz arbeitest. Verwende lieber separate Variablen, also vec3 position und float size.
    Dies gilt nur für lokale Variablen im Shader. Wenn du mit dieser Methode Werte in einer Textur zusammenfassen kannst ist dies natürlich sehr sinnvoll!
  6. Überlege ob du aufwendige Berechnungen, z.B. ein Partikelsystem, nicht besser vollständig auf der Grafikkarte realisierst. Stichworte: Framebuffer-Objects und Transform-Feedback.

Quellen