Entwickler-Ecke
Multimedia / Grafik - opengl glLineWidth zu langsam
uall@ogc - Do 08.05.08 14:44
Titel: opengl glLineWidth zu langsam
Folgendes Problem:
Ich habe ca. 1 Mio Koordinaten die ich mit glBegin(GL_LINE_STRIP) zeichne. Um das zu beschleunigen hab ich das in eine Liste (glNewList) ausgelagert.
Das funktioniert super und ist schnell genug.
Wenn ich nun aber die Linienbreite erhöhe, dann ist das total langsam.
Delphi-Quelltext
1: 2: 3:
| glNewList(FList, GL_COMPILE); glLineWidth(2); ... |
Das Problem dabei ist nicht etwa, dass glCallList(FList) ewig dauert (das geht gleich schnell), sondern SwapBuffers braucht auf einmal ewig lang!. Irgendwie kommts mir so vor, dass opengl wenn glLineWidth > 1 ist per GDI zeichnet.
Kennt jemand das Problem und weiß eventl. eine Lösung?
Martok - Do 08.05.08 14:59
Breite Linien zu rastern ist einfach wesentlich komplizierter... Bekannt ist mir das Problem also durchaus.
Wobei, 1 Million? Müssen die wirklich immer alle gerendert werden? Hier würde ich ansetzen, wenn ich das optimieren sollte.
Was renderst du denn schönes?
uall@ogc - Do 08.05.08 15:16
ja ggf müssen alle gerendert werden.
Wenn ich aber statt ner Linie, nen QUAD zeichne (was dann bisl dicker ist) gehts wieder schnell.
Zwischen 20msek und 780msek im Durchschnitt ist es aber für die doppelte Breite schon bisl krass. Das sind 50FPS vs 1FPS...
Warum SwapBuffers so lange dauert is nu klar, denn erst da werden die Daten an die Graka geschickt (gdi32.ExtEscape)
Lossy eX - Do 08.05.08 15:28
OpenGL arbeitet asynchron. Du darfst also nicht immer davon ausgehen, dass der Aufruf abgearbeitet ist sobald er zurück kommt. Besonders bei Displaylisten/VBOs. Die Wartezeit kommt immer dann zum Tragen, wenn eine Operation aufgerufen wird die vorraussetzt, dass alle Operationen abgeschlossen sind. So zum Beispiel beim Swapen. Dann muss die Grafikkarte komplett fertig gezeichnet haben. Oder es wird eben gewartet.
Die Breite der Linien hat mitunter einen starken Einfluss auf die Geschwindigkeit. Alleine schon, weil eine breitere Linie bedeutet, dass die Grafikkarte doppelt so viele Pixel in den Buffern befüllen muss. Je nach Karte kannst du da auch sagen. Größe * 2 = Geschwindigkeit / 2.
OpenGL unterscheidet 2 Linientypen. SMOOTH und normalen Linien. Setzen kannst du dies mit glHint(GL_LINE_SMOOTH_HINT, GL_NICEST oder GL_FASTEST);. Ich denke was da was ist sollte selbsterklärend sein.
Außerdem haben die Linien einen Größenbereich den die Karte unterstützen. Die Je nach Linientyp kannst du die Größen mit glGetIntegerfv(GL_LINE_WIDTH_RANGE; (array [0..1] of single;)) und glGetIntegerfv(GL_SMOOTH_LINE_WIDTH_RANGE, ...) erfragen. Dabei werden 2 Werte zurückgeliefert. Erste Stelle min und zweite max.
So eine wirklichen Lösungsvorschlag dazu kann ich dir leider nicht geben. Das Einzige was evtl etwas bringt ist das Smoothing zu entfernen (fastest). Falls das bereits der Fall ist, dann kann es auch an der Grafikkarte liegen. Aktuell werden die Karten primär nur auf Polygone optimiert und so etwas wie Linien etc sind nur noch rudimentär vorhanden. Es kann auch gut sein, dass der Treiber bei dir in den Softwaremodus umschaltet. Wenn es Faktor ~ 50+ langsamer ist, dann wird es auf der CPU berechnet. Das ist leider ein Trend den die Großen der Branche vermehrt einschlagen.
uall@ogc - Do 08.05.08 15:50
Danke erstmal, ich hab nen kleines TestProg geschrieben, was das Problem verdeutlicht (glLineWidth = 2) dann dauerts bei mir 10 mal so lang.
Vielleicht kann das mal jemand testen. Ich habe hier eine Matrox Karte drin... eben aus meinem Projekt extrahiert :)
EDIT: Hab gerade damit nen PC gecrasht oO. Also vorher mal alles speichern :)
Martok - Do 08.05.08 16:04
Ähm, wieso geht das bei dir?
Eigentlich kann man auf das Desktop-Window kein Handle holen, weil man das Pixelformat nicht ändern kann...
Yogu - Do 08.05.08 16:04
Hallo,
ich würde dein Programm ja gerne testen, aber da kommt immer ein "unbekannter Softwarefehler". Was mich an dem Code wundert: Du erstellst nirgends ein Fenster - und genau an der Stelle, als du den Rendering Context zum nicht vorhandenen Fenster erstellen willst, kommt bei mir der Fehler. Wie wohin willst du eigentlich zeichnen? Klappt das bei dir wirklich?
Vielleicht kannst du deine Frage auch nochmal im
DelphiGL [
http://www.delphigl.com] posten - das ist ein Forum, das sich ausschließlich um OpenGL dreht.
Grüße,
Yogu
Mist, zu spät :(
uall@ogc - Do 08.05.08 16:06
ähm ja war eben zusammengeschustert, habs uach aufn nem anderen Rechner getestet, da kam auch nen Fehler.
Ich glaub ich muss ma ne kleine Testapp schreiben bei der man auch was sieht.
BenBE - Do 08.05.08 16:10
Bei mir schmiert's Programm auch weg (GeForce 7600 GTX - Notebook ;-)).
Lossy eX - Do 08.05.08 16:15
Alternativ kannst du auch mal
glView [
http://www.realtech-vr.com/glview/] bei dir ausprobieren. Der zeigt alle möglichen Extension und Min/Max Werte von OpenGL an. Aber frag mich nicht wo. Ich habe gerade nur gesehen, dass die die Oberfläche komplett geändert haben.
Zeichnen auf Desktop. Man kann ein Pixelformat nur einmal pro DC auswählen. Aber ich meine es geht auch, wenn man keines auswählt. Aber dann hat man unter Umständen keinen Doublebuffering was wiederum keinen Sinn machen würde. Aber Fenster solltest du wirklich machen. Wer weiß was der Treiber alles optimiert, wenn kein Fenster da ist. Hier gings im übrigen. Aber die Karte ist sehr beschränkt, weswegen die Ergebnisse (2x 1) rein gar nichts aussagen!
PS: Du hast dir ne Matrix aus deinem Projekt extrahiert? ;)
[edit]PPS: Es gibt seit geraumer Zeit eine neue
dglOpenGL.pas [
http://wiki.delphigl.com/index.php/dglOpenGL.pas] (die ohne .NET). Dort wurde einiges an Balast entfernt.
uall@ogc - Do 08.05.08 16:37
hier ein neues Beispiel:
Matrox Graka: Linie(1) = 200msek (1.mal) danach 30msek
Matrox Graka: Linie(2) = 900msek (immer)
Nvidia Graka: Linie(1) = 0msek
Nvidia Graka: Linie(2) = 0msek
alias5000 - Do 08.05.08 17:04
ATI (Radeon 9600 XT): beides mal 0
Yogu - Do 08.05.08 17:11
NVIDIA GeForce4 MX 4000:
Breite 1: ca. 550 ms
Breite 2: ca. 800 ms
Ich möchte noch anmerken, dass ich einfache OpenGL-Anwendungen durchaus mit 60 FPS rendern kann...
Lossy eX - Do 08.05.08 19:29
Also beim ersten Mal immer 16ms und anschließend ziemlich genau 0ms. Ist beim ersten Mal evtl die Displaylistengenearion dort mint enthalten oder zu knapp davor? Mit deaktivierter OpenGL Beschleunigung liegt das immer bei ca 94 und 359ms. Also nicht nur das Doppelte sondern fast das Vierfache.
Yogu - Do 08.05.08 19:48
Lossy eX hat folgendes geschrieben: |
Also beim ersten Mal immer 16ms und anschließend ziemlich genau 0ms. |
Falls hier
GetTickCount verwendet wird, heißt dass nichts. Wenn die Zeit unter einer Grenze liegt, kommt immer so etwas um den Dreh raus. Wenn du das nicht schon tust,
uall@ogc, solltest du lieber
QUERYPERFORMANCECOUNTER verwenden. Das geht bis auf Mikrosekunden genau.
Grüße,
Yogu
Lossy eX - Do 08.05.08 21:37
Mich würde mal interessieren wie viele Linien das jetzt waren und wie viele davon außerhalb des Bild waren. Meines Wissens nach clippen einige Treiber Geometrie die außerhalb liegt. Was dann erwartungsgemäß schneller gehen sollte. Beim Messen solltest du auch berücksichtigen, dass es komplett fertig arbeitet. Also inklusive SwapBuffer.
uall@ogc - Fr 09.05.08 08:36
Ja SwapBuffer ist in der Messung drin, Anzahl der Linien waren 500k
Es wird auch GetTickCount genutzt, was aber in meinem Fall ausreicht.
Ob nun geclipt wird is mir auch egal. Es geht mir daraum, dass auf manchen Grakas, der 1. Aufruft mit glLineWidth(1) lange dauert, danach realtiv schnell. Aber bei glLinewidth(2) manchmal mehr um das 4 Fache dauert. ich hab Schwankungen von dem 4-30!! fachen im Gegensatz zu glLineWidth(1)
@Yogu:
NVIDIA GeForce4 MX 4000:
Breite 1: ca. 550 ms
Breite 2: ca. 800 ms
Das sind normale Werte. Das glLineWidth(2) bis doppelt so lange dauert bei einer alten Graka passt schon.
Wenns aber > 4mal so lange dauert, glaub ich immer es wird per GDI gezeichnet oO
Lossy eX - Fr 09.05.08 09:40
uall@ogc hat folgendes geschrieben: |
Wenns aber > 4mal so lange dauert, glaub ich immer es wird per GDI gezeichnet oO |
Die Treiber sind leider in der Lage fehlende Funktionalität selber nachlegen zu dürfen. Von OpenGL wird nur die Schnittstelle definiert. Aber es hat niemand gesagt, dass es alles per Hardware gemacht werden muss. Leider gibt es auch keine Möglichkeit so etwas zu erfragen. Das merkt man dann meistens wenn es zu langsam ist.
Mein klassisches Beispiel in diesem Fall sind die Chipreihen der Radeon 9700 etc. Texturen die als Größe keine Potenz von 2 haben werden unterstützt aber sobald MipMaps aktiv sind verfällt der Treiber in einen Softwaremodus. Es werden aber auch nur die Texturen im Treiber berechnet und sollten diese klein genug sein so fällt das kaum auf. Genau genommen hätten also die 9700er kein OpenGL 2.0 unterstützen dürfen. Zu mindest wenn alles in Hardware hätte sein müssen. Aber NVidia macht so etwas auch. Ich meine nur da war es was mit Shadern.
Zu der Verzögerung bei der ersten Benutzung. Ich kann mir gut vorstellen, dass beim ersten Aufruf verschiedene Dinge auf der Krafikkarte initialisiert werden müssen. Das ist aber wieder vollkomme Sache des Treibers weswegen man das nicht genau sagen kann. Spontan würden mir da aber 2 Dinge einfallen.
1) Entweder erzeugt das erste Mal swappen so einen Effekt. Glaube ich aber eher nicht. Bin aber auch schon überrascht worden. Das kann man aber auch recht einfach testen. Einfach vorher mal nen SwapBuffer auf einen leeren Buffer machen und schauen ob sich was tut.
2) Oder aber die Displayliste wird erst bei der ersten Benutzung wirklich zur Grafikkarte übertragen. Das glaube ich schon eher. Denn auf modernen Grafikkarten werden innerhalb der Displaylisten
Vertex Buffer Objects [
http://wiki.delphigl.com/index.php/Tutorial_Vertexbufferobject] benutzt. Damit liegen die Vertexdaten auf der Grafikkarte. Das geht aber nur wenn man genau weiß wie groß die Daten sind. Was bei einer DL für den Treiber nicht möglich ist bzw. frühstens erst bei glEndList.
Um das zu umgehen kannst du direkt VBOs benutzen. Die Daten kann man dann auch nachträglich ändern und muss nicht alles neu erstellen lassen. Auf richtig alten Karten oder welche ohne Datenspeicher werden aber keine VBOs in Hardware unterstützt. Aber NVidia hat es da im Treiber nachgebaut und ich meine ATI auch. Aber diese Lösung ist dann nicht oder nur kaum schneller als wie wenn man mit VertexArrays oder iterativ rendert.
BenBE - Fr 09.05.08 09:44
nVIDIA GeForce 7600 GTX
Beide Male 0ms; selbst bei 1440x1050 Fensterauflösung ;-)
Delete - Fr 09.05.08 15:26
bei mir bricht dein programm ab. "windows hat ein problem festgestellt und muss beendet werden..."
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!