Wie kann ich _why_ glDrawArrays sehr langsam debuggen?

7

Ich arbeite an einem Spiel, das CEGUI und Ogre verwendet. Kürzlich haben wir festgestellt, dass einige unserer Kunden mit GeForce4 MX 4000 eine schreckliche Leistung erzielen.

Nach einer Nacht mit dem Debuggen habe ich das Problem auf einen glDrawArrays-Aufruf im Ogre GL Renderer zurückgeführt. Die meisten Ausführungen dieses Aufrufs sind ziemlich schnell (<10 ms, was immer noch scheiße ist, aber für diese schreckliche Karte in Ordnung ist). Eine Ausführung der Renderfunktion GLRenderSystem :: _ dauert jedoch 3500 ms pro Frame.

Es wird nur eine TRIANGLE_LIST mit 54 Elementen gezeichnet. Bei allen anderen Aufrufen werden TRIANGLE_LISTs ähnlicher Größe gezeichnet, sodass nicht die Größe des Arrays oder sein Typ das Problem darstellt.

Ich habe:

  • deaktivierte Fragment-Shader (der GF4 MX unterstützt sie nicht)
  • deaktivierte Vertex-Shader (es unterstützt sie, aber CEGUI kann nur alle Arten von Shadern oder keinen von ihnen ausführen)
  • Es wurde versucht, einen Anruf in der Nähe für Multitexturing zu deaktivieren
  • Die Benutzeroberfläche, die ich zeichne, wurde massiv vereinfacht, sodass es sich nur um ein einziges CEGUI :: Window handelt

Aber ich schieße wirklich nur im Dunkeln. Ich bin in einer Windows-Umgebung. Was ist ein gutes Werkzeug, um den OpenGL-Status zum Zeitpunkt eines Funktionsaufrufs herauszufinden? Ich vermute, dass es eine besonders schweinische Textur oder einen Fragment-Shader gibt, der irgendwie durchrutscht und gerendert wird.

Wenn es keine Tools gibt, die das tun, was ich brauche, kann jemand Vorschläge machen, wie glDrawArrays auf einer alten Karte wirklich langsam gemacht werden können?

Aktualisieren:

  • Ich griff nach GLTrace und verglich die Aufrufe, die sowohl einem schnellen als auch einem langsamen glDrawArrays vorausgingen. Sie sind absolut identisch, sie binden sogar die gleichen Textur-IDs.
  • Ein konsistenter Unterschied besteht jedoch darin, dass der Aufruf, der langsam ausgeführt wird, der erste in jedem OGRE / Cegui-Rendering-Frame ist. Möglicherweise werden Texturdaten in jedem Frame auf die Grafikkarte kopiert (was lächerlich wäre und auf anderen Karten eindeutig nicht vorkommt ...). Update: Dies ist nicht der Fall - egal wo in der Warteschlange ich das fehlerhafte Objekt zeichne, es dauert immer noch ewig. Siehe unten.
  • Es werden 3 Hauptobjekte gezeichnet: ein Hintergrund mit vollem Fenster (normales Weiß, wird mit einer 128x128-Textur strukturiert), eine kleinere rechteckige Beschriftung und Text in dieser Beschriftung. Die Verhältnisse zwischen ihren Ziehgeschwindigkeiten sind ungefähr gleich den Verhältnissen zwischen ihren Flächen
  • Wenn ich erzwinge, dass das langsame Objekt mehrmals gezeichnet wird, anstatt die gesamte Renderwarteschlange zu zeichnen, ist es jedes Mal langsam, was bedeutet, dass es sich nicht um ein einmaliges Ladeproblem handelt.

Update für die aktuelle Theorie: Dies ist irgendwie ein Problem mit der Füllrate. Gibt es eine Möglichkeit, ein Fenster so zu konfigurieren, dass die Karte Probleme beim Ausfüllen hat? Wenn ich im Fenstermodus zeichne, wird das manchmal eine Karte durcheinander bringen? Mein Fenster hat keine Zweierpotenz-Dimensionen (oder Dimensionen, die einer Standardauflösung ähneln). Könnte das ein Chokepoint sein?

ArtHare
quelle
Vertex-Puffer jeglicher Art verwenden?
Sean Middleditch
1
Sie könnten gDEBugger versuchen .
Nathan Reed
Das hört sich so an, als ob die GPU blockiert. Wurden die verwendeten Texturen oder Vertex-Puffer im aktuellen Frame geändert?
Archy
1
Offensichtlich. Haben Sie einen bestimmten Profiler, den Sie verwenden, oder können Sie ihn für OpenGL-spezifische Profilerstellung empfehlen? Ich habe eine Tonne sehr schläfrig verwendet, aber da es den Aufrufstapel im nVidia-Treiber nicht auflösen kann, war es nicht hilfreich. Außerdem weiß ich durch einfaches Durchgehen genau, welcher Anruf langsam ist.
ArtHare
1
@ user1158478: glBufferData, glBufferSubData und glGenBuffers sind diejenigen, nach denen gesucht werden muss. Sie sollten glGenBuffers nur während des Ladens aufrufen und glBufferData sparsam verwenden. Denken Sie daran, Puffer vor dem Aktualisieren zu verwerfen, wenn Sie sie in diesem Frame bereits verwendet haben. Es gibt keine garantierte GL-Möglichkeit, dies in einer Version zu tun, die von dieser alten Hardware unterstützt wird, aber Treiber erlauben normalerweise einen Hack dafür, indem sie glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_DYNAMIC_DRAW)( GL_ARRAY_BUFFERgegebenenfalls ersetzen ) verwenden.
Sean Middleditch

Antworten:

6

Ich habs:

  1. Der Geforce4 MX mit den neuesten verfügbaren nVidia-Treibern (ca. 2006) unterstützt den glTexEnv-Ansatz zum Mischen von Quell- und Zieltexturen nicht. Zumindest nicht in Hardware. Das Zeichnen der einfachsten Formen führt zu einer lähmenden Langsamkeit.
  2. Es scheint jedoch GL_BLEND in Kombination mit glBlendFunc in der Hardware zu unterstützen.

Lösung: Anstelle des komplizierten Cegui-Setups siehe unten:

glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_EXT)
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_EXT,GL_MODULATE)
glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_RGB_EXT,GL_TEXTURE)
 glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_RGB_EXT,GL_PRIMARY_COLOR_EXT)
glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE2_RGB_EXT,GL_CONSTANT_EXT)
glTexEnvi(GL_TEXTURE_ENV,GL_RGB_SCALE_EXT,GL_LINES)
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_RGB_EXT,GL_SRC_COLOR)
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND1_RGB_EXT,GL_SRC_COLOR)
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND2_RGB_EXT,GL_SRC_ALPHA)
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_ALPHA_EXT,GL_SRC_ALPHA)
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND1_ALPHA_EXT,GL_SRC_ALPHA)
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND2_ALPHA_EXT,GL_SRC_ALPHA)
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_EXT)
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_ALPHA_EXT,GL_MODULATE)
glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_ALPHA_EXT,GL_TEXTURE)

Ich werde das tun: glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)

Wenn Sie als zukünftiger Leser auch Ihr OgreGLRenderSystem ändern, werde ich diese Änderung in GLRenderSystem :: _ setTextureBlendMode in OgreGLRenderSystem.cpp vornehmen.

ArtHare
quelle
Autsch! Ich wusste, dass es schlecht war, aber ich habe nie bemerkt, dass es so schlecht war. Ich würde tatsächlich vermuten, dass es eher eine minimalere Teilmenge von Modi unterstützt und etwas darin darüber gestolpert ist. Vielleicht konstant als Quelle2? (Die GL_LINES für die RGB-Skala ist in Ordnung, da GL_LINES als 1 definiert ist. Sieht aus wie ein Fehler in dem, was Sie zum Speichern der Aufrufe verwendet haben.)
Maximus Minimus
1
Wenn der bedingte Wechsel zu glBlendFunc funktioniert, werde ich dort wahrscheinlich einfach aufhören. Ich habe viele Stunden nach diesem Problem geworfen, und es gibt andere Bereiche, an denen ich arbeiten muss. Insbesondere hat die Karte kein GL_EXT_blend_func_separate, was mich denken lässt, dass die getrennte Mischung von RGB und Alpha, die Ogre versucht, möglicherweise nicht funktioniert.
ArtHare
Wenn es für Sie gut funktioniert, gibt es keinen Grund, hier nicht aufzuhören.
Maximus Minimus
1

Ich habe es auch verstanden. Für mich war es ein Problem mit der Textur. Auf NVIDA lief es schnell. Aber meine optische Optimierung führte dazu, dass eine ATI-Karte schnell zurücktrat.

Ich arbeite mit einer Textur der Größe 4720 x 5600 (ungefähr) und moderne Karten funktionieren gut damit.

Ich habe versucht, Ränder mit Wrapmode = GL_CLAMP_TO_BORDER_ARB zu optimieren. Daher muss ich glTeximage2D das Randargument als mindestens == 1 liefern. Da die fragliche Karte in HW keine Grenze unterstützte, stellte sich heraus, dass es für einen Frame 20 Sekunden dauerte. Wenn Sie zu GL_CLAMP_TO_BORDER + border param == 0 zurückkehren, wird die Geschwindigkeit wieder erhöht.

Robetto
quelle