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

Aktuelle Zeit: Di Mai 14, 2024 22:36

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



Ein neues Thema erstellen Auf das Thema antworten  [ 10 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Re: RenderThread und resitz problem
BeitragVerfasst: Mi Okt 16, 2013 10:46 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Zuerst einmal, ist wichtig, dass OpenGL ein Context auf den Thread bindet, auf dem er erzeugt wurde und nicht von anderen Threads aufgerufen werden sollte/kann(es gibt wohl treiber die es trotzdem erlauben).
Das bedeutet, der Thread, der den rendercode ausführt, muss auch den Context erzeugen(nicht das Fenster).
Damit der Context erzeugt werden kann, muss der Fensterhandle übergeben werden.
Windows schaut z.B. anhand des DeviceContext, welcher Render Context wglMageCurrent switchen soll, denn jeder Context ist einem Thread zugewiesen und diese Infos werden über den DeviceContext bezogen.

Man kann also nicht das Fenster und den Render Context im Hauptthread erzeugen und dann im Renderthread rendern.
Wo und wer das Fenster erzeugt ist geschmacks Sache aber der Render Context muss im render Thread erzeugt werden und dieser braucht den DC( GetDC() ) von der Fenstererzeugung.

Wenn man mit mehreren Fenstern und Render Context arbeitet, dann muss man auch beachten, dass OpenGL API nicht auf Multithreading ausgelegt ist und man immer zwischen den Render Context switchen muss, wenn man auf diesen arbeiten will.
glCurrent switcht zu dem passendem Render Context, der auf dem aktuellen Thread gebunden ist und kann dann darauf arbeiten.

Ein weiteres Problem ist, bei Multithreaded die Koordinierung von Fenster Event Handling und Rendern.
Üblicherweise wird unter Windows sämtliche Event Message Handling auf dem Hauptprozess gemacht(früher war es auf diesen Prozess beschränkt, heute könnte das schon anders sein, da leg ich mich nicht fest) aber die Fenster können auf anderen Threads laufen und das rendering wieder auf einem anderem.
Das Problem ist, der Hauptprozess bekommt ein Fenster Resize Event, das wird aufgelöst, indem die WndProc Funktion, die für das Zielfenster hinterlegt wurde aufgerufen wird.
Aber im gleichen Moment render der Render Thread und da kommen sich der Hauptprozess und der Renderprozess in die Quere.

Ich hab es in meinen Scene Editor wie folgt gelöst.
Code:
  1. // wird vom renderthread aufgerufen
  2. void ViewerForm::Render(const IObserver* Sender)
  3. {
  4.     Scopelock lock(*m_RenderLock);// erlaubt nur Render oder SizeChanged aus zu führen, sonnst muss gewartet werden
  5.     m_Canvas->MakeCurrent();
  6.  
  7.     glViewport(0, 0, m_Canvas->ProjectionMatrix.GetSize().Width, m_Canvas->ProjectionMatrix.GetSize().Height);
  8.     glMatrixMode(GL_PROJECTION);
  9.     glLoadMatrixf(m_Canvas->ProjectionMatrix.GetMatrix(Viewtype::View2D).Value);
  10.     glMatrixMode(GL_MODELVIEW);
  11.     glLoadMatrixf(m_Modelview.Value);
  12.  
  13.     m_Canvas->Clear();
  14.  
  15.     m_Context->Update();
  16.     m_Context->Render();
  17.  
  18.     m_FileWatcher.ProcessBuffer();
  19.     m_Canvas->SwapBuffer();
  20.     m_FPS.Update();
  21. }
  22. // wird vom Hauptprozess aufgerufen, kann aber auch vom renderthread aufgerufen werden
  23. void ViewerForm::SizeChanged(const Size2D<>& Size)
  24. {
  25.     Scopelock lock(*m_RenderLock);// erlaubt nur Render oder SizeChanged aus zu führen, sonnst muss gewartet werden
  26.  
  27.     Rocket::Core::Vector2i dim;
  28.     dim.x = Size.Width;
  29.     dim.y = Size.Height;
  30.     m_Context->SetDimensions(dim);
  31.  
  32.     m_Canvas->MakeCurrent();
  33.     glMatrixMode(GL_PROJECTION);
  34.     glLoadMatrixf(m_Canvas->ProjectionMatrix.GetMatrix(Viewtype::View2D).Value);
  35.     glMatrixMode(GL_MODELVIEW);
  36.     glLoadMatrixf(m_Modelview.Value);
  37.     glClearColor(0, 0, 0, 1);
  38. }


Das war aber nicht der Weisheit letzter Schluss, denn in einer Gameloop wäre ein Mutex einfach nur schlecht.
Die bessere Lösung ist, dass diese Informationen in einer JobQueue an den Renderthread geschickt werden, dieser kann dann vor der Render Funktion alle Jobs abarbeiten und hat dann kein Mutex, welches Locked.
Code:
  1. void ViewerForm::Render(const IObserver* Sender)
  2. {
  3.     m_Canvas->MakeCurrent();
  4.  
  5.     m_JobQueue.ProcessAllJobs();
  6.  
  7.     glMatrixMode(GL_PROJECTION);
  8.     glLoadMatrixf(m_Canvas->ProjectionMatrix.GetMatrix(Viewtype::View2D).Value);
  9.     glMatrixMode(GL_MODELVIEW);
  10.     glLoadMatrixf(m_Modelview.Value);
  11.  
  12.     m_Canvas->Clear();
  13.  
  14.     m_Context->Update();
  15.     m_Context->Render();
  16.  
  17.     m_FileWatcher.ProcessBuffer();
  18.     m_Canvas->SwapBuffer();
  19.     m_FPS.Update();
  20. }
  21.  
  22. static void ResizeCommand(const Size2D<> Size)
  23. {
  24.     Rocket::Core::Vector2i dim;
  25.     dim.x = Size.Width;
  26.     dim.y = Size.Height;
  27.     InstancePointer->m_Context->SetDimensions(dim);
  28.     glViewport(0, 0, m_Canvas->ProjectionMatrix.GetSize().Width, m_Canvas->ProjectionMatrix.GetSize().Height);
  29. }
  30.  
  31. void ViewerForm::SizeChanged(const Size2D<>& Size)
  32. {
  33.     m_JobQueue.Enqueue(ResizeCommand, Size);
  34. }

_________________
"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: RenderThread und resitz problem
BeitragVerfasst: Mi Okt 16, 2013 13:26 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Du solltest mal mit GetCurrentThreadId in der Render und Resize Funktion ausgeben oder mit Breakpoints mal auf die ThreadIDs gucken. Ich gehe davon aus, dass VCL das event handling nur primitiv mapped und dann wären es 2 threads.

Allerdings, wenn ich mir deine DoOnVisTimer Methode angucke, dann bekomme ich das Gefühl, dass es ein simpler Programierfehler mit Pointern ist.
Sicher dass FShareMemPointer zu jedem Zeitpunkt mindestens sizeof(DWORD)*71 Byte groß ist ?
Unabhängig davon würde ich statt der Magic Numbers wenigstens KONSTANTEN verwenden, damit man schneller raus lesen kann, was das soll.

_________________
"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: RenderThread und resitz problem
BeitragVerfasst: Mi Okt 16, 2013 14:48 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Nov 08, 2010 18:41
Beiträge: 769
Programmiersprache: Gestern
woher kommt denn VisInfo^.VisBuf?

_________________
Meine Homepage


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: RenderThread und resitz problem
BeitragVerfasst: Mi Okt 16, 2013 20:32 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Okey fangen wir von vorne an.
Deine Fehlermeldung sagt, dass er nicht auf ein MMX Register von der FPU zugreifen konnte, weil es z.B. gerade beschrieben wird.
Dies passiert, wenn man z.B.
Code:
  1. var vec:^MyVector;
  2. begin
  3.   vec:=Bla;
  4.   vec^=SomeOtherVec;
  5. end;
  6.  
  7. ...
  8. begin
  9.   vec:=Bla;
  10.   LocalVec := vec^;

in 2 Threads aufteilt und z.B. der Speicher größer als eine Cache-Line ist.

Ich muss hier mal kurz ausholen.
Multithreading funktioniert nur ohne Mutex, wenn die Operation eine Atomic Operation ist.
Die meisten Operationen sind nicht Atomic Operation aber es gibt einige und MovAps ist Atomic, wenn die Daten auf einer Cache-Line liegen.
Was ist eine Cache-Line? Eine CPU kopiert sich Speicher in die einzelnen CPU Caches Level 1 und aufwärts.
Die höheren Caches sind größer und langsamer und die niedrigen kleiner und schneller.
Wenn man also auf ein Speicher zugreift, dann kopiert er größe Bereiche in z.B. L3 Cache, ein kleineren teil in L2 und 64Byte in L1.
L1 ist der Speicher, mit dem die ALU und FPU arbeiten.
Wenn nun ein Array von 512Bytes als Vector Liste dient, dann kopiert er eventuell die ganzen 512Byte in L3, 128Byte in L2 und 64Byte in L1.
Sagen wir dein Vector liegt bei offset 48Byte, dann kann er die letzen 12 Byte von der Cache-Line, im L1 Cache, in einen der MMX register kopieren. Das ohne Probleme von mehreren Threads gelesen und geschrieben werden, denn die Operationen sind in dem Fall Atomic.
Sagen wir nun, dass der Vector bei offset 60Byte liegt, dann kann er 4 Byte von der Cache-Line ziehen, kopiert sich aus dem L2 Cache die nächste Cache-Line in L1 und kopiert die restlichen 12 Byte vom Anfang. Dies kann nicht mit mehreren Threads arbeiten, denn die Operation ist nicht mehr Atomic.
Nun noch der 3. Fall, der Vector liegt bei Byte 47Byte, dann kann er 1 Byte von der Cache-Line 32-48 kopieren, dann 15Byte von der Cache-Line 48-64 kopieren und das zusammen wursten. Das ist auch nicht Thread safe, denn dies braucht auch mehr als eine Operation.

Deswegen ist SIMD ein bisschen aufwändiger zu meistern, man muss wissen wie es funktioniert, man sollte immer Memory Aligned auf 128Bit(16Byte) arbeiten und nicht mit anderen Daten mixen. Tut man es doch oder kann es nicht garantieren, dann muss man Mutex benutzen, während man darauf arbeitet.

Um nun wieder zu der Problematik zu kommen, du scheinst irgendwo in der Resize Funktion ein Vektor aus dem Speicher zu verwenden, welcher von einer anderen Stelle und Thread ebenfalls verwendet wird und die Daten sind nicht korrekt Memory Aligned.

_________________
"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: RenderThread und resitz problem
BeitragVerfasst: Mi Okt 16, 2013 21:20 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Ich weiß nicht wie der Timer in VCL genau funktioniert, von daher kann ich nur Vermutungen anstellen.
Windows bietet mehrere API's für Timer, eine läuft über den Hauptprozess, wenn die Event Messages abgearbeitet werden und eine weitere ist wirklich Async in einem Hardware Thread vom OS und dann gibt es die Möglichkeit, dass die ein eigenen Thread starten und dort ledeglich ein smartes SleepEx verwenden.

Wenn eine Operation nicht Thread safe ist und diese von 2 Threads aufgerufen wird, dann kann es irgendwann krachen, je nach wie schnell und mit welchen Offset diese ihre Arbeit machen. Es gibt Fälle, da fällt das erst nach Tagen auf.
Die längste Zeit war knapp 1 Monat, bis ein solcher Fehler in einem Produktiv Server von mir auf trat.
Wird die gleiche Operation aber nacheinander in einem Thread ausgeführt läuft diese Problemlos.

OpenGL kommt mit mehreren Threads klar, man muss halt nur vor dem ersten OpenGL Befehl immer ein wglMakeCurrent aufrufen, damit die folgenden Befehle an einen gültigen Context wandern.

Das erste was ich machen würde ist herraus zu bekommen, was wann und wo ausgeführt wird und dann mal nach zu gucken ob es an ein Speicherblock liegt, den du alloziiert hast aber nicht korrekt aligned wurde.
Je nach pascal, freepsacal oder delphi version gibt es dort diverse Möglichkeiten und Probleme.
Delphi7 hat sich z.B. sehr pissig, das es 8Byte alignment vor sieht und MMX aber auch 16Byte braucht.

Ich lehne mich mal ganz weit aus dem Fenster und sage, dass du vieleicht auf deinem Shared Memory das Rect oder teile von Position und Größe ablegst und es nicht 16Byte Alignment hat, weil 8Byte üblich ist und für 16Byte extra Code geschrieben werden muss.
Wenn dann noch die Variablen gepackt werden oder nicht ein vielfaches von 16Byte als Offset im Array hat, dann kann genau das passieren, was bei dir passiert.

_________________
"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: RenderThread und resitz problem
BeitragVerfasst: Mi Okt 16, 2013 21:51 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Du tust in der Resize Funktion den Device Context neu erzeugen, sobald der zerstört wird sollte auch der Render Context hinüber sein(leider nicht Spezifiziert und Treiber abhängiges Verhalten).

Das einzige, was man beim Resize Event machen sollte ist glViewport neu aufrufen und wenn notwendig die Matrizen neu berechnen.
Code:
  1.     // projection matrix neu berechnen
  2.     m_Canvas->MakeCurrent(); // den zu dem thread passenden RenderContext binden
  3.     glViewport(0, 0, m_Canvas->ProjectionMatrix.GetSize().Width, m_Canvas->ProjectionMatrix.GetSize().Height); // Viewport vom Context updaten, damit das Fenster vollständig gemalt wird und die Aspect Ratio stimmt
  4.     glMatrixMode(GL_PROJECTION);// projektion matrix updaten
  5.     glLoadMatrixf(m_Canvas->ProjectionMatrix.GetMatrix(Viewtype::View3D).Value);
  6.     glMatrixMode(GL_MODELVIEW);// model matrix updaten
  7.     glLoadMatrixf(m_Modelview.Value);

_________________
"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: RenderThread und resitz problem
BeitragVerfasst: Mi Okt 16, 2013 23:08 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Nov 08, 2010 18:41
Beiträge: 769
Programmiersprache: Gestern
EWeiss hat geschrieben:
Zitat:
woher kommt denn VisInfo^.VisBuf?

wird mit CreateDIBSection erstellt.

gruss


Ok hier scheint dein Problem wohl zu liegen. Probier mal folgendes:
Code:
  1.  
  2. gdipBitmapLockBits
  3. glTex....
  4. glFinish&Flush
  5. gdipBitmapUnlockBits
  6.  

_________________
Meine Homepage


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: RenderThread und resitz problem
BeitragVerfasst: Do Okt 17, 2013 08:16 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Nov 08, 2010 18:41
Beiträge: 769
Programmiersprache: Gestern
Hi,
Ja das liegt aber weder an OpenGL noch an GDI. Du hast naemlich das Kleingedruckte ueberlesen:

OpenGL und GDI arbeiten nicht synchron mit deinen Programm. Sprich manche Befehle sind nicht zwingend abgeschlossen wenn die Funktion wieder in dein Programm springt. Wenn du die ganze Zeit im gleichen Context arbeitest faellt das nur sehr selten ins Gewicht. Im Gegenteil, es ist sogar besser auf diese Weise zu arbeiten. Sobald du aber mit zwei verschiedenen Sachen arbeitest gibts schnell Probleme.
Nimm zum Beispiel die CreateDIBSection Funktionen. Diese gibt nur einen Pointer zu den Bitmap Daten stellt aber nicht sicher das Pointer nichtmehr irgendwo anders verwendet wird. Man muss also dafuer sorgen das GDI nichts mehr mit den Daten macht bevor man Sie verwendet (gdiFlush bzw. glFlush + glFinish sind hier die Zauberwoerter).

Allerdings ist sowas nur eine Notloeung da diese Asynchrone Arbeitsweise ja schneller ist. Daher sollte man das ganze so wenig wie Moeglich machen. Besonders dann wenn es doppelt geschehen muss wie hier. Das ganze im Resize zu machen ist also schon von Anfang bis Ende "broken by Design". Einen einfachen Workaround: Solange der User noch beim Resize ist die alten Texturen verwenden. Also sowas wie :wenn 60ms kein Resize". Aber wie gesagt, ist halt einfach beschissen :)

_________________
Meine Homepage


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: RenderThread und resitz problem
BeitragVerfasst: Do Okt 17, 2013 12:30 
Offline
DGL Member
Benutzeravatar

Registriert: Di Dez 03, 2002 22:12
Beiträge: 2105
Wohnort: Vancouver, Canada
Programmiersprache: C++, Python
Das was ich jetzt sage ist komplett offtopic, daher schon mal sorry dafür... aber, Eweiss: Es heißt "resize", nicht "resitz"... normalerweise korrigiere ich niemanden, aber da es sich hier nicht um einen einfachen vertipper zu handeln scheint dachte ich, es wäre eventuell ganz angebracht :)

Es wäre super, wenn jemand den Thread titel entsprechend ändern könnte, allein schon damit zukünftige Leute eine Chance haben den Thread über die Suche zu finden :)

Aya


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: RenderThread und resitz problem
BeitragVerfasst: Do Okt 17, 2013 15:35 
Offline
DGL Member
Benutzeravatar

Registriert: Di Dez 03, 2002 22:12
Beiträge: 2105
Wohnort: Vancouver, Canada
Programmiersprache: C++, Python
EWeiss hat geschrieben:
Zitat:
Eweiss: Es heißt "resize", nicht "resitz"...

Frau Aya oder wer auch immer.
Waren sie mal Krank hatten mit Gehirnblutung zu tun, mußten sich erst wieder neu orientieren, Nein?
Das freut mich für sie.
Das man mitunter einiges vergessen hat scheint dabei nur logisch somit nehme ich ihren Hinweis gerne
für die Zukunft entgegen. :)

Nur damit sie wissen wie schwer es ist zurück ins Leben zu finden. (siehe meine vielen Edit's bei meinen Beiträgen)
Aber kein Mitleid. Danke.

Öhm... ich kann auch meine Klappe halten und Leute einfach ihre Fehler endlos lange wiederholen lassen, wenn das eher gewünscht ist. Ich persönlich bin immer ganz froh wenn mir jemand sagt das ich einen Fehler unwissentlich immer wiederhole, oder das mir was aus der Nase hängt oder meine Schminke verrutscht ist.

Zudem könnte es Ihnen ja auch bei Ihrer Suche nach der Fehlerquelle helfen wenn sie darauf hingewiesen werden dass es "Resize" und nicht "Resitz" heißt, zumindest Google dürfte zu ersterem ein paar mehr Treffer liefern als zu letzterem (was jetzt nicht implizieren soll, dass sie gefälligst jetzt Google nutzen sollen - nur als Beispiel gemeint)

Übrigens, aus welchen Gründen ein Fehler begangen wird ist für die anderen meist nicht ersichtlich.
Und wie ich schon schrieb, ich korrigiere normalerweise Rechtschreibfehler nicht - meist bemerke ich sie garnicht. Aber in diesem Fall fiel mir halt die konsequente Falschschreibung auf, weswegen ich dachte das ein hinweis eventuell ganz angebracht wäre.

Beim nächsten mal halte ich einfach meine klappe, denke mir meinen Teil und gut ist.

Aya

PS: Sorry für Offtopic..


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


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 19 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:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.044s | 17 Queries | GZIP : On ]