Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: So Dez 22, 2024 04:01

Foren-Übersicht » Programmierung » OpenGL
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 7 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Optimierung
BeitragVerfasst: Di Dez 16, 2014 01:12 
Offline
DGL Member
Benutzeravatar

Registriert: Di Apr 29, 2008 18:56
Beiträge: 1213
Programmiersprache: Delphi/FPC
Hey,

ich hab grad einen Beitrag von TAK gelesen und würde den gern als Diskussions-Grundlage nutzen im ein paar Fragen zu klären.
TAK2004 hat geschrieben:
Nvidia hat in ihrer letzten Präsi Zero Driver Overhead 2.0 Command List auch mal Zahlen genannt.
Große Spiele haben in der Regel 2500 Draw calls und 11k-12k Function Calls.
Man hat also auf jeden Draw call ca 5 state changes Funktionen und viele von den kosten soviel wie der Draw call.
Jedes BindTexture, BindShader oder gluniform ist ein State change.
Daher ist es auch besser State changes zu reduzieren und das macht man üblicherweise durch sortieren der Objekte und Draw calls nach deren Shader und Texturen.
Diese sortierung ist um einiges einfacher und bringt so unglaublich viel für den Aufwand.
Wir haben bei unserer Engine die Objekte zur Zeit in einem Baum abgelegt, wo jeder Knoten die relative Position des Objekts (sprich die Matrix) zum Eltern-Knoten speichert. Gerendert wird dann einfach indem der Baum in einer Tiefensuche abgelaufen wird und an jedem Knoten entsprechen Push-, Mult- und PopMatrix gecallt wird.
Nach TAKs Aussage wäre es aber sinnvoller den Baum anhand der zu bindenden OpenGL Objekte aufzubauen. Wie funktioniert das dann mit den Positionen der Objekte? Speichert man die dann absolut für jedes Objekt? Kostet das nicht haufen Rechenzeit auf der CPU? Oder löst man das ganz anders?

MfG Bergmann.

_________________
Aktuelle Projekte: BumpMapGenerator, Massive Universe Online
Auf meiner Homepage gibt auch noch paar Projekte und Infos von mir.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Optimierung
BeitragVerfasst: Di Dez 16, 2014 08:13 
Offline
DGL Member
Benutzeravatar

Registriert: Di Sep 06, 2005 18:34
Beiträge: 362
Wohnort: Hamburg
Ich trenne dazu Scene-Graph und Renderer von einander.
D.h. der Scene-Graph enthält zwar die Objekthierarchie zum Berechnen der Matrizen aber die zeichenbaren Objekte werden dennoch in einer flachen liste im Renderer gespeichert und der ignoriert den Aufbau der Scene dann komplett.
Das ermöglicht es die Objekte nach ganz anderen Kriterien zu sortieren als im Scene-Graph, braucht aber auch mehr Aufwand wenn man dann wieder Informationen aus dem Scene-Graph effizient verarbeiten möchte. Was meines Erachtens nach aber nicht so wichtig ist.

_________________
Der Mensch hat neben dem Trieb der Fortpflanzung und dem zu essen und zu trinken zwei Leidenschaften: Krach zu machen und nicht zuzuhören. (Kurt Tucholsky)
Schwabbeldiwapp, hier kommt die Grütze. (Der Quästor)


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Optimierung
BeitragVerfasst: Di Dez 16, 2014 10:36 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2622
Wohnort: Berlin
Programmiersprache: Go, C/C++
Ein SceneGraph sollte prinzipiell nicht die Grundlage deiner Gamewelt sein, dieser ist ausschliesslisch für Grafische Objekte gut geeignet.
Hoch skalierbare Systeme, wie sie in den großen Engines zum Einsatz kommen benutzen ein Entity Component oder Fast Entity Component System und das Render System hat ein SceneGraph, welcher die speziellen eigenheiten von 3D rendering abdeckt.
Der SceneGraph ist auch nicht gut geeignet um die Welt zu aktualisieren, denn der ist nicht effizient parallelisierbar aber gut für das abarbeiten, wenn man ein Frame rendern will.
Es ist also zu empfehlen eine Component auf den Entities zu haben die die Transformation enthält und diese dann updated.

In mein Zero Prime Projekt z.B. benutze ich ein Fast Entity System und es gibt RenderBehaviour, PlanetRendererBehaviour und einige andere Components, welche sich ein Transform auf dem Entity teilen.
Die Transform liegt im Entity, nicht bei der Komponente und ich kann dann z.B. eine Physic Component bauen und im Process wird dann die Transform vom Entity erneuert.
Nun kommt der Vorteil von Fast Entity Component Systemen zum tragen.
Ein PhysicManager oder Renderer Manager kann im Process nun alle Entities parallel im ThreadPool updaten.
Code:
  1. RF_Algo::ForEach(m_RenderComponents, ...

Wenn man allerdings Hierachien wie z.B. eine Burg enthält ein Marktplatz, dann kann man das nicht einfach parallel abarbeiten.
Daher ist es besser diese auf zu lösen und alle Objekte nebeneinander mit absoluten Positionen zu halten aber in z.B. einer Transform Componente dann transformationen mit diesen Hierachy zu modifizieren.
Hier ist dann auch ein SceneGraph praktisch, der kennt die Hierachy und kann dann alle Entities raus suchen, die wir transformieren müssen und dann wendet man wieder mit ForEach auf diese Liste an(für z.B. Editor).

Die Sichtbarkeit, Occlusion Test kann man z.B. in dem Entity System prüfen und dann die Z sortierung und batchen über den SceneGraph machen.
Am einfachsten ist es mit GPUPerf Studio oder NSight mal den Frame Debugger zu starten und zu gucken welche States am häufigsten kommen und nach diesen die Sortierung aus zu legen.
Da kann man leider nicht spezieller werden, weil jedes Game und Render Engine anders funktioniert und entsprechend andere States mehr auftreten.
Wie schon erwähnt hat Physical Based Rendering in der Regel nur 2 Shader Programme und da macht es Sinn erst diese zu sortieren und dann mal nach den Uniforms zu gucken(häufig das Problem) oder Texturen.
Ich empfehle UBO ein zu bauen, das reduziert die last enorm und ist ab OpenGL 3 verfügbar bzw. als Extension und ARB vorher.
Dort packt man dann die Kamera Matrizen und Globale Shader settings wie z.B. Frametime(für z.B. prozedurales Wasser, motion blur oder tone mapping).

Edit:
UBO haben noch den Vorteil, dass die Updates praktisch keine Sync Points erzeugen und damit wesentlich weniger Zeit als normale gluniform aufrufe kosten.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Optimierung
BeitragVerfasst: Di Dez 16, 2014 13:25 
Offline
DGL Member
Benutzeravatar

Registriert: Di Apr 29, 2008 18:56
Beiträge: 1213
Programmiersprache: Delphi/FPC
Okay,

hab ich erstmal weitestgehend verstanden. Leider lässt sich das in unserer Engine jetzt nicht so einfach ändern ohne nochmal alles aufzureißen :/
Vlt ein paar kurze Worte dazu wie es zur Zeit ist. Das ganze ist eine DeferredEngine uns ist folgendermaßen aufgebaut:
- Objekte sind im SzeneGraph gespeichert (mit relativen Positionen)
- Objekte besitzen ein Model
- ein Model besitzt wiederum einen SzeneGraphen, dessen Knoten andere Modelle oder RenderObjects enthalten
- ein RenderObject kombiniert ein Mesh und ein Surface
- das Mesh ist ein einfaches VBO (noch keine VAOs die stehen noch auf der ToDo-Liste)
- das Surface beinhaltet alles was die Oberfläsche des Objekts beschreibt: Material, Texturen und den dynamisch erstellten Shader. Texturen sind bis zu 3 Stück (Colormap, Normalmap und Lightmap).
Gerendert wird - wie schon gesagt - einfach mit ner Tiefensuche auf dem SzeneGraph(en). Ein Suface bindet alle Materialien und Texturen, das Mesh ruft das VBO auf und danach entbindet das Surface wieder alles. Das binden des Surfaces ist in einer DisplayListe gespeichert (das hatte es aber nicht wirklich schneller gemacht). Sind also sehr viel StateChanges drin :?
Ich würde das dann so optimieren das ein Graph angelegt wird, indem jede Ebene eine der folgenden Dinge ist (Reihenfolge vorerst egal, guck ich mir mit gDEBugger mal an): Shader, Colormap, Normalmap, Lightmap, VBO/VAO.
Was denkst du wieviel sich das Performance-Technisch optimieren lässt? Wenn wir nur von 1-2% reden, dann lohnt sich der Aufwand fast nicht. Bei 10-20% würde das schon ganz anders aussehen und wir sollten da vlt wirklich nochmal Zeit reinstecken.

€: noch dazu kommt das die DeferredEngine ja in RenderPasses arbeitet und ein Surface unter Umständen mehrmals mit verschiedenen Shadern aufgerufen wird. Das Surface entscheidet das selbst anhand des aktiven RenderPasses.

MfG Bergmann.

_________________
Aktuelle Projekte: BumpMapGenerator, Massive Universe Online
Auf meiner Homepage gibt auch noch paar Projekte und Infos von mir.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Optimierung
BeitragVerfasst: Di Dez 16, 2014 17:22 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2622
Wohnort: Berlin
Programmiersprache: Go, C/C++
In Prozenten zu reden ist schwer, weil das Bottleneck nicht bekannt ist.
Meine Empfehlung ist als erstes mit dem Visual Studio 2013 Concurrency Analyzer sich an den Process zu hängen und zu gucken wer der Blocker ist.
Wenn du z.B. OpenGL auf einem eigenen thread hast und Objekte und so von einem anderen kommen oder IO Threads da rein gretschen, dann wirst du sehen, dass dein Renderthread rote balken enthält. Rote Balken sind schlecht, denn dein Renderthread wartet auf wen anderes ^^
Sind rote Balken auf dem Thread, wo die Gameloop läuft, dann ist da auch schlecht.
Solche Blöcke sollten in der Zeitdauer gemessen werden und sind Nr. 1 bei Optimierung.

Dann kannst du mit Visual Studio Nsight oder GPU Perfstudio dir angucken, was die last erzeugt, Perfstudio ist halt für AMD und ich hab da wesentlich bessere erfahrung gemacht. Das sagt dir sogar einige Bottlenecks und funktioniert auch bei schlimmsten Programmcode ohne ab zu stürzen.
Beide tools sagen dir welcher OpenGL Befehl wieviel Zeit auf CPU und GPU verbracht hat.
Ein opengl Befehl, der mehr als 1us auf der GPU braucht ist in der Regel ein Syncpoint, diese willst du raus optimieren und nun kannst du anfangen diese zusammen zu rechnen und bekommst dann die Zeit raus, die du sparst und damit auch die % an Performance.

Dann ist wichtig zu sehen, wielange die einzelnen Draw calls auf der GPU brauchen und CPU.
Bei mir z.B. braucht ein Drawcall 2-3us(egal ob 6 tris oder 6k tris) und ein uniform setzen 2-4us, Shader Variablen setzen 2us, wenn man auf jeden Drawcall 5 statechanges hat die soviel wie der Drawcall kosten, dann bekommst du eine ganz neue Palette an Optimierungspotenzial.
Sind z.B. viele Textur bindings drin, dann kannst du mit einem Texturarray von 512, 1024 und 2048 einiges bewirken.
Pack einfach die am wenigsten genutzen Texturen in das Array und sortiere dann deine Objekte.
Nutzt die 16 Texturslots aus oder nutzt gleich Bindless Textures(OpenGL 4), wenn möglich.
Nutzt deine Daten, indem du einfach alles, was nicht animiert oder Physik besitzt zusammen gemerged wird.
Damit kannst du ne menge matrizen setzen raus werfen.
Für kleine VBO solltest du auf ein Index Buffer Object verzichten, klein sind hier prinzipiell alles unter ~1k tris. Das VBO wird größer aber das IBO binding fällt weg und GPU Perfstudio sagt dir dies auch für einzelne VBO die im aktuellen Frame gerendert wurden.
Erst bei einigen hundert tris greift der Cache messbar, wenn man IBO verwendet.
Werfe glGetError komplett raus, nutzt KHR_DEBUG in dev Version und verzichte bei Release komplett drauf.
Das ist so extrem teuer.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Optimierung
BeitragVerfasst: Di Dez 16, 2014 18:17 
Offline
DGL Member
Benutzeravatar

Registriert: Di Apr 29, 2008 18:56
Beiträge: 1213
Programmiersprache: Delphi/FPC
Okay, dann mach ich erstmal die Analyse mit den Tools eh ich schon wieder alles umbau. Erstmal gucken wann ich das alles machen soll :?
Auf jedenfall erstmal vielen Danke für die Tipps, wenn ich dann soweit bin meld ich mich nochmal. :)

_________________
Aktuelle Projekte: BumpMapGenerator, Massive Universe Online
Auf meiner Homepage gibt auch noch paar Projekte und Infos von mir.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Optimierung
BeitragVerfasst: Di Dez 16, 2014 20:40 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2622
Wohnort: Berlin
Programmiersprache: Go, C/C++
Da ist mal ein Link über States, Sync points und OpenGL 3-4 Lösungen.
http://gdcvault.com/play/1020791/
Command list
https://developer.nvidia.com/sites/default/files/akamai/gameworks/events/gdc14/AvoidingCatastrophicPerformanceLoss.pdf
Ich kann dir leider nur die slide geben, das video dazu ist nur für gdcvault member und konnte kein rip im Netz finden.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 7 Beiträge ] 
Foren-Übersicht » Programmierung » OpenGL


Wer ist online?

Mitglieder in diesem Forum: Google [Bot] und 14 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
cron
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.018s | 17 Queries | GZIP : On ]