|
Das deutsche QBasic- und FreeBASIC-Forum Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
schildron
Anmeldungsdatum: 25.08.2008 Beiträge: 86
|
Verfasst am: 18.09.2012, 20:43 Titel: OpenGL + ThreadCall Problem |
|
|
Hallo FreeBASIC Profis!
Ich will bei meinem aktuellen Computerspiel sowohl OpenGL als auchThreadCall einsetzen.
Leider tritt folgendes Problem auf:
Ich kann in einem mit ThreadCall gestartenem Sub keine Vertexe zeichnen; egal ob ich mutexe einsetze oder nicht. Werden die Subs ohne Threadcall aufgerufen, werden beide Dreiecke einwandfrei angezeigt.
Hier der Code mit Mutexen:
Code: |
'-------------------------
'DIMs
'-------------------------
Dim Shared As String Tastendruck
'-------------------------
'Includes
'-------------------------
#Include "fbgfx.bi"
#Include "GL/gl.bi"
#Include "GL/glu.bi"
'-------------------------
'Declarationen
'-------------------------
Declare Sub Objekt1(tlock1 As Any Ptr)
Declare Sub Objekt2(tlock1 As Any Ptr)
'-------------------------
'Textausgabe in Konsole
'-------------------------
Dim Shared DateiNr As Integer
DateiNr = FreeFile
Open Cons For Output As #DateiNr
'-------------------------
' das Fenster öffnen
'-------------------------
Screen 19, 16, , 2
'-------------------------
' Open-GL Init
'-------------------------
glViewport 0, 0, 800, 600 ' den Current Viewport auf eine Ausgangsposition setzen
glMatrixMode GL_PROJECTION ' Den Matrix-Modus Projection wählen
glLoadIdentity ' Diesen Modus auf Anfangswerte setzen
gluPerspective 45.0, 800.0/600.0, 0.1, 100.0 ' Grundeinstellungen des Anezeigefensters festlegen
glMatrixMode GL_MODELVIEW ' Auf den Matrix-Modus Modelview schalten
glLoadIdentity ' und auch diesen auf Anfangswerte setzen
glClearColor 0.5, 0.5, 0.50, 0.0 ' Setze Farbe für löschen auf Mittelgrau
glClearDepth 1.0 ' Depth-Buffer Löschen erlauben
glEnable GL_DEPTH_TEST ' den Tiefentest GL_DEPTH_TEST einschalten
glClear GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT 'Tiefen- und Farbpufferbits löschen
'---------------------------
'HAUPTTEIL
'---------------------------
Dim tlock1 As Any Ptr = MutexCreate()
Do Until Tastendruck = Chr(27) :'die Schleife solange immer wiederholen, bis in der Variablen Tastendruck die Esc-Taste (chr(27) steht
'---------------------------
'ProgrammSchleife
'---------------------------
glClear GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT
Tastendruck = InKey 'Jeder Tastendruck wird sofort in die Variable Tastendruck gespeichert
Dim Vertex1 As Any Ptr = ThreadCall Objekt1(tlock1)
Dim Vertex2 As Any Ptr = ThreadCall Objekt2(tlock1)
'Dim tlock1 As Any Ptr
'Objekt1(tlock1) '<<<<<<<<<<<<<<<<hier die neue Programmzeile rein
'Objekt2(tlock1)
ThreadWait Vertex1
ThreadWait Vertex2
Flip 'liebes OpenGL, zeig alles, was in der Schleife für dich vornedran steht, auf Monitor an
'---------------------------
'Ende der Schleife
'---------------------------
Loop
MutexDestroy tlock1
Close #DateiNr
End
'-------------------------
Sub Objekt1 (tlock1 As Any Ptr)
'hier kommen die Programmzeilen zum Anzeigen
'von dem Dreieck rein
Print #DateiNr, "O1 aufgerufen!"
MutexLock tlock1
glBegin gl_TRIANGLES
glColor3f 1.0,1.0,0.0 :' Zeichenfarbe auf gelb
glVertex3f 0.5, 1.0, -6.0 :' der erste Punkt
glVertex3f -0.5, 1.0, -6.0 :' der erste Punkt
glVertex3f 0.0, 2.0, -6.0 :' der erste Punkt
glEnd
MutexUnlock tlock1
End Sub
Sub Objekt2 (tlock1 As Any Ptr)
'hier kommen die Programmzeilen zum Anzeigen
'von dem Dreieck rein
MutexLock tlock1
glBegin gl_TRIANGLES
glColor3f 1.0,1.0,0.0 :' Zeichenfarbe auf gelb
glVertex3f 0.5, -1.0, -6.0 :' der erste Punkt
glVertex3f -0.5, -1.0, -6.0 :' der erste Punkt
glVertex3f 0.0, 0.0, -6.0 :' der erste Punkt
glEnd
MutexUnLock tlock1
End Sub
|
Ich hoffe es ist nur ein kleiner Fehler, ich arbeite erst seit kurzer Zeit mit Threads und wahrscheinlich übersehe ich irgendetwas.
Ich hoffe hier kann mir jemand helfen in Threads Dreiecke zu zeichnen. |
|
Nach oben |
|
|
Jojo alter Rang
Anmeldungsdatum: 12.02.2005 Beiträge: 9736 Wohnort: Neben der Festplatte
|
Verfasst am: 18.09.2012, 20:48 Titel: |
|
|
10 Sekunden googeln:
http://www.opengl.org/wiki/OpenGL_and_multithreading
-> Du benötigst höchstwahrscheinlich http://wiki.delphigl.com/index.php/wglMakeCurrent um dem Thread überhaupt zu sagen, wo er denn hinzeichnen soll.
BTW: Threadwechsel sind teuer und langsam. Das Zeichnen von Objekten auf mehrere Threads auszulagern (vor allem mit Mutexen, die noch mal langsamer sind!) ist keine gute Idee. Separiere lieber Programmlogik und Zeichenaufrufe in zwei verschiedene Threads.
Das Zeichnen eines Objektes dauert wesentlich als der Verwaltungsoverhead aller Threadfunktionen hier, d.h. dein Programm wird mit Threads langsamer, nicht schneller. Erst ab einer gewissen Funktionsgröße macht es überhaupt Sinn, diese in einen eigenen Thread zu packen. Ein dutzend OpenGL-Aufrufe liegen sicherlich unter dieser Größe. _________________ » Die Mathematik wurde geschaffen, um Probleme zu lösen, die es nicht gäbe, wenn die Mathematik nicht erschaffen worden wäre.
|
|
Nach oben |
|
|
28398
Anmeldungsdatum: 25.04.2008 Beiträge: 1917
|
Verfasst am: 19.09.2012, 12:32 Titel: |
|
|
Drawcalls werden immer aus einem und v.a. dem gleichen Thread gemacht. Immer. API-unabhängig.
/e: Also um das vielleicht etwas besser auszudrücken: Drawcalls werden immer aus dem gleichen Thread gemacht, allerdings kann es durchaus Sinn ergeben einen anderen Thread oder mehrere Threads* zum Upload von Texturen und Meshes zu nutzen. Allerdings wird man dann meistens eher context-sharing o.ä. nutzen, weil man eher nicht möchte, dass der Treiber seine command list(s) sperrt, nur weil man gerade im Hintergrund Texturen nachlädt
* nur wenn man schon vorher konzeptionelle Fehler gemacht hat. Warum? Wenn das Laden von Texturen/Meshes, also den Daten, die in rauen Mengen vorliegen, CPU-bound ist, hat man bereits einiges falsch gemacht. Und wenn sie, wie sie sein sollten, IO-bound sind, dann bringen mehrere Threads auch nichts mehr.
Ein tolles Negativbeispiel ist Oblivion (Skyrim?) bei dem das Laden von Leveldaten fast vollständig CPU-bound ist, aber nicht parallelisiert wurde. Tja
/e2: (Nur weil ich gerade langeweile habe) Wenn du jetzt deinen eigenen Rendering-Thread hast, in dem du alle Drawcalls abhandelst, und einen seperaten Upload-Thread und noch weitere Threads für Ton und game logic, stellt sich natürlich die Frage, wie du das synchronisiert kriegst ohne allzu häufig langsame multi-threading primitiven wie locks zu verwenden.
Nach meinem Kenntnisstand ist das übliche Verfahren, die Threads so wenig wie möglich zu koppeln (ist ja eh logisch) und möglichst einbahnige producer->consumer-beziehungen herzustellen. wenn man dann noch für die kommunikation zwischen den threads asynchrone mittel nimmt und für das bereitstellen von daten datenstrukturen, die atomar aktualisiert werden können, hast du das problem praktisch schon gelöst.
wenn du nämlich alles schon bei der konzeption sauber in nur definiert interagierende teile filettiert hast, lösen sich die meisten probleme hier von selbst. ein nachteil der losen synchronisation ist natürlich, dass es bei verzögerungen in einem thread zu inkonsistenten ausgaben kommen kann, also z.b. hängenden ton und flüssiges bild oder ein kurz stehendes bild, weil ein texturenmanager scheiße gebaut hat und eine textur nicht früh genug precached hat und erst auf die HDD warten muss, während der ton einfach weiterläuft. aber sowas sind keine beinbrüche.
as i said: saubere trennung, definierte schnittstellen und "unverletzliche" datenstrukturen
simple "unverletzliche" datenstruktur? nun, wie wäre es mit einem producer-consumer-"pipe"/array?
zwei felder in der nativen wortbreite:
offset
length
daten
daten
daten
der producer schreibt jetzt im laufe des produzierens seine daten dahinter, die daten sollten dabei ne fixe länge haben, also meistens pointer. das juckt den consumer nicht. keine synchro hier erforderlich
jetzt is der producer fertig und will dem consumer die daten zur verfügung stellen
er schreibt also atomar den neuen length wert, den der consumer sieht und weiterarbeitne kann, mit den neuen daten.
wenn der consumer mit einem element fertig ist schriebt er einfach an offset die position des fertigen elements, geht atomar, weil native wortbreite (je nach arch, aber spätestens mit amd64 geht das).
jetzt hast du nur noch das kleine problem, dass die liste wandert. durch den heap. nicht gut.
dafür gibts verschiedene lösungsansätze, kommst sicher selber drauf.... is ja kein sonderlich komplexes problem... |
|
Nach oben |
|
|
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
|