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

Aktuelle Zeit: So Jun 16, 2024 03:22

Foren-Übersicht » Programmierung » Einsteiger-Fragen
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 23 Beiträge ]  Gehe zu Seite 1, 2  Nächste
Autor Nachricht
BeitragVerfasst: Mo Jan 13, 2014 12:12 
Offline
DGL Member

Registriert: Mi Mai 04, 2011 16:09
Beiträge: 11
Hallo Leute

Ich habe schon diverse kleine Ausgaben mit OpenGl progammiert, sowohl 3D als auch 2D-Darstellung. Dieses Forum hat mir dabei auch sehr geholfen. Momentan habe ich aber ein Problem, bei dem ich alleine nicht weiter komme. Es handelt sich um ein Programm, für das ich eine konstante, gleichmäßige Bewegung in 2D-Darstellung benötige. Dies habe ich per VSync realisiert und erhalte dadurch eine butterweiche Bewegung mit 60 FPS, soweit so gut.

Mein Problem ist nun, dass ich regelmäßig ca. 1 mal pro Sekunde in der fließenden Bewegung einen „Ruckler“ drin habe. Das Auftreten ist anscheinend unabhängig von der Geschwindigkeit des Rechners, ich habe es auch auf anderen Rechnern getestet. Die Ruckler treten außerdem abhängig von der verwendeten Ausgabegröße auf, im Vollbild eher als bei kleinen Fenstergrößen.

Die Ruckler lassen sich nur abstellen, wenn ich zu Beginn jeder Renderschleife ActivateRenderingContext(DC, RC) anstelle einfach nur wglMakeCurrent(DC, RC) aufrufe. Hierbei werden zusätzlich die ImplementationProperties und Extensions eingelesen. Letzteres verlangsamt mein Programm aber so sehr, dass ich auf großen Auflösungen (4K) keine ruckelfreie Ausgabe (dann 24 FPS) mehr hinbekomme.

Ich habe schon versucht, die Prozessorwechsel mittels SetProcessAffinityMask zu vehindern, kein Erfolg. Das Einfügen von kleinen Sleeps oder weiteren wglMakeCurrent vor oder nach SwapBuffers bringt teilweise Erfolge aber nicht sicher für alle Fenstergrößen.

Also zusammengefasst lautete meine konkrete Frage:
Wie kann ich Auflösungs-unabhängig eine VSync-Ausgabe ohne Ruckler in 2D erreichen?

PS:
Ich verwende Delphi7 und nVidia Grafikkarten, ich habe 2 Bildschirme, die aber beide mit 60 Hz in derselben Auflösung angesteuert werden. Das Problem tritt auch auf anderen Systemen mit nur einem Bildschirm auf.
Ich habe mir erlaubt, einen Beispielcode anzufügen…

Grüße,
Delfit


Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jan 13, 2014 14:18 
Offline
DGL Member

Registriert: Do Dez 29, 2011 19:40
Beiträge: 421
Wohnort: Deutschland, Bayern
Programmiersprache: C++, C, D, C# VB.Net
Normal ist das sicher nicht und den Zusammenhang mit Extensions verstehe ich auch nicht.
Auch wenn es möglicherweise keine wirkliche Lösung für das Problem ist, rufe doch einfach "wglMakeCurrent" nicht mehr auf. Einmal am Anfang reicht doch völlig. Dann ist der Context aktiviert und solange du nicht mit mehreren Contexts arbeitest und im selben Thread nochmal einen anderen Context aktivieren willst, ist der wiederholte Aufruf von "wglMakeCurrent" doch total überflüssig.

Meine eigentliche Vermutung wäre, dass etwas ganz anderes schief läuft.

Außerdem verwendest du noch deprecated OpenGL, das kann unter neueren Grafikkarten möglicherweise auch ein Performanceproblem darstellen und ist nicht Zukunftssicher.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jan 13, 2014 14:45 
Offline
DGL Member

Registriert: Mi Mai 04, 2011 16:09
Beiträge: 11
Hi

Danke für die schnelle Antwort! Das ich den Renderkontext nicht jedesmal aktivieren muss ist mir im Prinzip klar. Mein Programm soll jedoch 2 unabhängige Darstellungen liefern, daher muss ich jedesmal zwischen den Kontexten wechseln. Ich habe die Frage daher erstmal für die Verwendung von nur einem formuliert, weil der Effekt hier schon auftritt.

Warum der Aufruf von ActivateRenderingContext(DC, RC) das Ruckeln in allen Auflösungen behebt ist mir auch unklar. Ich könnte mir hier höchstens Seiteneffekte vorstellen, weil der Aufruf Zeit beansprucht oder das Lesen einer bestimmten Extension irgendwas im Treiber zurücksetzt...

Vielleicht hast du Recht und es hängt mit dem veralteten Code auf einer neuen Graka zusammen. Das würde bedeuten ich müsste alles in OpenGL3 schreiben. Ich hatte bisher vermutet, dass die "alten" OpenGl Befehle noch unterstützt verden, also in diesem Sinne nur alt, aber nicht "deprecated" sind, ich werde mich genauer informieren.

Ich werde es zunächst hiermit versuchen: http://www.delphigl.com/forum/viewtopic.php?f=10&t=11037

Leider gibt es noch kein Tutorial für den Einsteig von 0 auf OpenGl3 und viele andere Tutorials/Beispiele verwenden Code wie ich... Naja vielleicht schreibe ich ja selber eines, wenn ich durchblicke ;-)


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jan 13, 2014 16:55 
Offline
DGL Member

Registriert: Mi Mai 04, 2011 16:09
Beiträge: 11
Hallo Forum

Aufgrund der bisherigen Antwort müsste ich einen Test mit OpenGl3 machen, das werde ich auch mittelfristig tun. Da mein eigentliches Programm (Nicht der oben übertragene Test) jedoch schon relativ viele Kommandos (glBegin/End etc) hat wäre es schön, vielleicht doch noch eine Lösung für OpenGl < 3 zu finden.

Hat noch irgend jemand eine Idee, was für ein VSync ohne Ruckeln mit OpenGl < 3 noch zu beachten sein könnte?


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jan 13, 2014 19:39 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Nov 08, 2010 18:41
Beiträge: 769
Programmiersprache: Gestern
Hi,
ich habe mal den Code in meinen eigenen Fenster unter C getestet und alles lief tadellose. Daher würde ich spontan mal behaupten das onIdle hier Probleme macht.

_________________
Meine Homepage


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jan 13, 2014 21:59 
Offline
DGL Member
Benutzeravatar

Registriert: Sa Aug 18, 2007 18:47
Beiträge: 694
Wohnort: Köln
Programmiersprache: Java
Der Vollständigkeit wegen, werfe ich mal http://wiki.delphigl.com/index.php/Timebased_Movement ein. Nur um sicher zu gehen.

Ohne es im Kontext genau zu analysieren, finde ich dieses
Code:
  1. pos:= (pos+1) mod 50;

recht fragwürdig. Hast du mal einen Sinus probiert? Oder etwas, dass garantiert keine Probleme am Ende seines Wertebereichs hat?

_________________
Es werde Licht.
glEnable(GL_LIGHTING);
Und es ward Licht.


Zitat aus einem Java Buch: "C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off"

on error goto next


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Di Jan 14, 2014 17:10 
Offline
DGL Member

Registriert: Di Jun 12, 2012 21:26
Beiträge: 112
Programmiersprache: Delphi
Das OnIdle Event war auch mein erster Gedanke, da ich damit selbst schon Probleme hatte. Aus eigener Erfahrung bin ich mir recht sicher, dass das OnIdle Event nicht regelmäßig aufgerufen wird und dass dadurch Ruckler entstehen. Abhilfe kannst Du schaffen, in dem Du entweder ein Timebased Movement verwendest (siehe Link von damadmax) oder eben kein Idle-Event. Den QueryperformanceCounter nur einmal im OnIdle aufrufen! Ich zitiere mich mal selbst ;-) :
Zitat:
Beim getrennten Aufruf des QueryPerformanceCounter für den Startwert und den Endwert vor und nach dem Rendern können gerade im OnIdle-Event unter Umständen erhebliche Abweichungen in der Zeitmessung auftreten.
.... und dadurch wieder Ruckler.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Di Jan 14, 2014 17:41 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Aug 14, 2013 21:17
Beiträge: 588
Programmiersprache: C++
subotai hat geschrieben:
Aus eigener Erfahrung bin ich mir recht sicher, dass das OnIdle Event nicht regelmäßig aufgerufen wird und dass dadurch Ruckler entstehen. Abhilfe kannst Du schaffen, in dem Du entweder ein Timebased Movement verwendest
Timebased Movement ist kein Mittel, um Ruckler zu vermeiden, sondern um Vorgänge auf verschieden schnellen Rechnern gleich schnell auszuführen. An einer konstanten Framerate führt kein Weg vorbei, wenn es nicht ruckelig aussehen soll. Siehe auch Framerate#Variation_der_Framerate.

_________________
So aktivierst du Syntaxhighlighting im Forum: [code=pascal ][/code], [code=cpp ][/code], [code=java ][/code] oder [code=glsl ][/code] (ohne die Leerzeichen)


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Di Jan 14, 2014 19:03 
Offline
DGL Member

Registriert: Di Jun 12, 2012 21:26
Beiträge: 112
Programmiersprache: Delphi
glAwesome hat geschrieben:
Timebased Movement ist kein Mittel, um Ruckler zu vermeiden, sondern um Vorgänge auf verschieden schnellen Rechnern gleich schnell auszuführen. An einer konstanten Framerate führt kein Weg vorbei, wenn es nicht ruckelig aussehen soll.
Man muss nicht alles glauben, was im Wiki steht. Laut Deiner Aussage wäre eine ruckelfreie Darstellung über das OnIdle-Event gar nicht möglich, da das OnIdle-Event keine konstante Framerate gewährleistet.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Di Jan 14, 2014 19:12 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Aug 14, 2013 21:17
Beiträge: 588
Programmiersprache: C++
In diesem Fall glaube ich es, weil ich es selbst geschrieben habe. Mit dem OnIdle-Event kenne ich mich nicht aus, aber Fakt ist, dass nur konstante (und hohe) Frameraten absolut flüssig aussehen. Die Begründung steht ja auch im Wiki-Artikel.

_________________
So aktivierst du Syntaxhighlighting im Forum: [code=pascal ][/code], [code=cpp ][/code], [code=java ][/code] oder [code=glsl ][/code] (ohne die Leerzeichen)


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Di Jan 14, 2014 20:04 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Sep 23, 2002 19:27
Beiträge: 5812
Programmiersprache: C++
Aus persönlicher Erfahrung würde ich die Finger vom OnIdle-Event weglassen, es gibt keine Garantie dass da nicht irgendein Prozess "reinpfuscht" und dafür sorgt dass man zwischen zwei OnIdle-Events unterschiedliche Zeitsprünge hat. Alles schon live und in Farbe selbst erlebt (auf eigenen und fremden Rechnern).

Von daher ganz klar eigene Renderschleife nach dem Erzeugen des Renderkontextes starten, in der gerendert wird bis eine Abbruchbedingung gegeben ist (z.B. Quit = True) und die am Ende eines jeden Durchganges Application.ProcessMessages aufruft :

Code:
  1. repeat
  2. QueryPerformanceCounter(QPCs);
  3. Render;
  4. UpdteEnvironment(dT);
  5. UpdatePhysics(dT);
  6. UpdateAudio(dT);
  7. Application.ProcessMessages;
  8. QueryPerformanceCounter(QPCe);
  9. dT := ...
  10. until Quit


Quit setzt man dann z.B. (wenn man die VCL nutzt) im CanClose des Formulars.

_________________
www.SaschaWillems.de | GitHub | Twitter | GPU Datenbanken (Vulkan, GL, GLES)


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Di Jan 14, 2014 20:37 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Sascha ist vollkommen zuzustimmen. Das OnIdle ist hochgradig frickelig. Selbst mausbewegungen habe ich da schon einfluss nehmen sehen.

grüße

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Jan 16, 2014 18:18 
Offline
DGL Member

Registriert: Mi Mai 04, 2011 16:09
Beiträge: 11
Hallo Leute

Erstmal danke für die vielen Hinweise!

Bei meinem Tool handels es sich um eine art Monitor-Testprogramm. Die Grundlage des Programmes (also das Problem dieses Threads) ist die Aufgabe, eine Abfolge von exakt definierten Frames hintereinander ausgeben zu können. Das teste ich zur Zeit unter anderem mit dem angegebenen Beispielprogramm mit den Balken, bei denen man eine Abweichung vom sanften Scroll sofort durch "Ruckeln" erkennt. Das Ruckeln entsteht hier nicht durch eine zu niedrige Framerate, sondern falls die Bewegung nicht immer genau einen Pixel (das nächste Frame) ausgibt, sondern auch mal 0 oder 2 Pixel pro Frame, falls bei der Ausgabe Frames verdoppelt oder übersprungen werden.

Eine Ausgabensteuerung mittels „timebased movement“ fällt daher flach, da das Timing der Ausgabe nicht auf einen internen Hardware/Software-Timer, sondern wirklich auf die Bildausgabe selbst, also auf das VSync synchronisiert werden soll. Die Geschwindigkeit der Szenen-Änderung richtet sich dementsprechend rein nach der Bildwiederholfrequenz.

Ich habe beobachtet, dass die Ruckler unterschiedlich stark auftreten je nach Ausgabemonitor oder Fenster/Vollbild Darstellung:
* Bei der Ausgabe auf nur einem 60-Hz Monitor im Vollbild läuft alles perfekt.
* Im Fenstermodus dagegen ruckelt es gleichmäßig.
* Bei Anschluss eines 2. (baugleichen) Monitores ist eine ruckelfreie Ausgabe auf keinem Bildschirm im Vollbild/Fenster zu realisieren.
* Bei Anschluss eines 2. Monitores mit 120 Hz ruckelt die Ausgabe auf diesem extrem aber es werden nachweislich Frames unterschlagen. Trotzdem zeigt mein inzwischen implementierter Framecounter exakt 120 FPS an...
* Bei Anschluss nur des 120 Hz Monitores ist alles wieder perfekt, aber nur im Vollbild. Hier kann ich exakt 120 definierte Bilder pro Sekunde übergeben, z.B. wird ein weiss/schwarz Wechsel als ruhiges, gleichmäßiges und stehendes grau wiedergegeben.

Bei allen Konfigurationenen außer einem einzelnen Monitor im Vollbild flackert ein derartiges Szenario unruhig und wechselt zwischen längeren Weiss- und Schwarzphasen, als ob nur jeder 2. Frame auch übertragen wird. Der Framecounter und der Monitor zeigen aber exakt die zu erwartenen Bildfrequenz.

Mein Eindruck ist, dass zum einen dem OpenGl Treiber nicht klar ist, auf welchen(!) Monitor er sich synchronisieren soll. Zum anderen scheinen auch bei regelmäßigen SwapBuffers mit korrekter Frequenz nicht alle Frames auch tatsächlich an der Grafikausgabe zum Monitor aktualisiert zu werden.

Zum Thema OnIdle:
Meine Renderschleife ist extrem kurz und verbraucht sehr wenig Rechenzeit. Ich sehe aber die Problematik der Zuverlässigkeit des Auftretens von OnIdle auch abhängig von der Hintergrundaktivität (Files öffnen, Virenscanner, Netzwerk etc.). Ich habe daher bereits die Prozesspriorität erhöht, aber ohne Wirkung.

Den Vorschlag, eine Hauptschleife zu verwenden und die Renderschleife mit ProcessMessages zu kombinieren finde ich reizvoll, allerdings stellt sich mir hier eine Frage:
Die Schleife wird ja nach Einsprung bis zum "Quit" nicht mehr verlassen... Wie springe ich sie also an? Wenn ich sie z.B. über einen Button starte, dann kommt ja die Behandlungsfunktion des Buttons nicht mehr zu Windows zurück... Führt der interne Aufruf von ProcessMessages dann nicht zu Verwirrung für das OS? Und wenn ich einen separaten Thread erstelle, kann ich in diesem dann ProcessMessages aufrufen? Ich denke an die Thread-Synchronisierung...

Ich hoffe, das war jetzt alles nicht zu technisch, letztlich möchte ich "nur" ein zuverlässiges vsync im 2.Modus... ;-)

Grüße
Delfit


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Jan 16, 2014 19:26 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Nov 08, 2010 18:41
Beiträge: 769
Programmiersprache: Gestern
Delfit hat geschrieben:
Den Vorschlag, eine Hauptschleife zu verwenden und die Renderschleife mit ProcessMessages zu kombinieren finde ich reizvoll, allerdings stellt sich mir hier eine Frage:
Die Schleife wird ja nach Einsprung bis zum "Quit" nicht mehr verlassen... Wie springe ich sie also an? Wenn ich sie z.B. über einen Button starte, dann kommt ja die Behandlungsfunktion des Buttons nicht mehr zu Windows zurück... Führt der interne Aufruf von ProcessMessages dann nicht zu Verwirrung für das OS? Und wenn ich einen separaten Thread erstelle, kann ich in diesem dann ProcessMessages aufrufen? Ich denke an die Thread-Synchronisierung...

Ich hoffe, das war jetzt alles nicht zu technisch, letztlich möchte ich "nur" ein zuverlässiges vsync im 2.Modus... ;-)

Grüße
Delfit


Hi,

Also da ja deine Frames exakt definiert sind kannst du ganz einfach folgendes machen:

Code:
  1.  
  2. int iframe = MAXIFRAME; //zähler für die frames
  3.  
  4. button_click... //click event
  5.   iframe = 0;  //zähler auf "start" setzen
  6. ...
  7.  
  8. repeat... //deine Render Schleife
  9.    wenn iframe < MAXIFRAME dann //irgendwo in deiner Schleife
  10.        zeige_frame(iframe); //zeige den aktuellen frame
  11.        iframe = iframe + 1 //gehe zum nächsten frame
  12.    ende wenn
  13.    ...
  14. until...
  15.  


Du könntest aber auch einfach den Button deaktivieren solange deine Schleife läuft. Oder nen Userthread erzeugen..... Ich lass deiner Kreativität mal freien Lauf :D

_________________
Meine Homepage


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Jan 17, 2014 09:24 
Offline
DGL Member

Registriert: Mi Mai 04, 2011 16:09
Beiträge: 11
Ich habe mitlerweile einen mehr schlecht als rechten Workaround gefunden: Sobald man Aero ausschaltet (anderes Theme wählen) funktioniert alles sauber und ohne Ruckler ohne zusätzliche Tricks oder Kniffe.
Das Problem liegt vielleicht nicht so sehr an OpenGl sondern an der Interaktion mit Windows...


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 23 Beiträge ]  Gehe zu Seite 1, 2  Nächste
Foren-Übersicht » Programmierung » Einsteiger-Fragen


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 85 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.098s | 17 Queries | GZIP : On ]