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

Aktuelle Zeit: Fr Jul 18, 2025 16:57

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



Ein neues Thema erstellen Auf das Thema antworten  [ 31 Beiträge ]  Gehe zu Seite 1, 2, 3  Nächste
Autor Nachricht
BeitragVerfasst: Sa Mär 15, 2008 22:07 
Offline
DGL Member

Registriert: So Jul 17, 2005 12:59
Beiträge: 89
Hallo,

ich schreibe zur Zeit an einem kleinen OpenGL Programm. Dieses verwendet unter anderem Texturen, und zwar viele. Da aber nicht alle immer benötigt werden, möchte ich einen Teil zur Laufzeit laden, sobald sie benötigt werden.

Dabei soll aber das Programm nicht unterbrochen werden. Genau das ist aber der Fall, wenn ich die Textur einfach nachlade. Daher habe ich nun das Laden der Textur in einen eigenen Thread ausgelagert, in der Hoffnung, dass die Hauptanwendung dann weiter läuft.

Doch leider ist genau das nicht der Fall. Es hat sich zur vorherigen Implementierung nichts geändert: Beim laden der Textur hängt das Hauptprogramm so lange, bis die Textur geladen ist.

Hier mein Quellcode:
Code:
  1.  
  2. unit Unit1;
  3.  
  4. interface
  5.  
  6. uses
  7.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  8.   Dialogs, StdCtrls, inifiles, dglOpenGL, Textures, math, ComCtrls;
  9.  
  10.  
  11. type
  12.   TForm1 = class(TForm)
  13.     Button1: TButton;
  14.     procedure FormActivate(Sender: TObject);
  15.     procedure Render();
  16.     procedure FormCreate(Sender: TObject);
  17.     procedure Button1Click(Sender: TObject);
  18.     procedure threadDone(Sender: TObject);
  19.  
  20.   private
  21.     { Private-Deklarationen }
  22.   public
  23.     { Public-Deklarationen }
  24.   end;
  25.  
  26.   // Texturlader-Thread
  27.   loadTexThread = class(TThread)
  28.   private
  29.     { Private-Deklarationen }
  30.   protected
  31.     procedure Execute; override;
  32.   end;
  33.  
  34. var
  35.   Form1: TForm1;
  36.  
  37.   // Texturen
  38.   background1, background2: gluint;
  39.  
  40.   //Test
  41.   rotState:real=0;
  42.  
  43.   //Threads
  44.   texLoadThread: loadTexThread;
  45.   anzT: integer=0;
  46.  
  47.  
  48. implementation
  49.  
  50. {$R *.dfm}
  51.  
  52. procedure loadTexThread.execute();
  53. begin
  54.    LoadTexture('gfx\bg1.jpg', background1, False);
  55.    Terminate();
  56. end;
  57.  
  58. procedure TForm1.threadDone(Sender: TObject);
  59. begin
  60.  // Load Texture has finished
  61.   if sender is loadTexThread then
  62.   begin
  63.    dec(anzT);
  64.   end;
  65. end;  
  66.  
  67. procedure TForm1.FormActivate(Sender: TObject);
  68. begin
  69.  Running := true;
  70.  
  71.  while running do
  72.  begin
  73.  
  74.   application.ProcessMessages;
  75.   render(); // Renders OpenGL
  76.  
  77.  end;
  78.  
  79.  close;
  80. end;
  81.  
  82. procedure TForm1.FormCreate(Sender: TObject);
  83. begin
  84.  
  85.   // Thread Init
  86.   texLoadThread := loadTexThread.Create(true);
  87.   texLoadThread.OnTerminate := threadDone;
  88.   texLoadThread.Priority := tpIdle;
  89.  
  90. end;
  91.  
  92. procedure TForm1.Button1Click(Sender: TObject);
  93. begin
  94.   anzT:=1;
  95.   texLoadThread.Execute;
  96. end;
  97.  
  98. end.
  99.  


Wieso ist das so, und was muss ich tun um mein Ziel zu erreichen?

Vielen Dank + Grüße
Pascal


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Mär 15, 2008 22:44 
Offline
DGL Member

Registriert: Di Jun 06, 2006 09:59
Beiträge: 474
du musst resume und nicht execute aufrufen.
Allerdings musst du beachten dass du OpenGL befehle nur im Hauptthread aufrufen darfst.

_________________
Bild


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Mär 15, 2008 22:48 
Offline
DGL Member

Registriert: So Jul 17, 2005 12:59
Beiträge: 89
Hi,

Danke für die Antwort. Mit Resume läuft die Anwendung tatsächlich weiter.
Leider wird die Textur trotzdem nicht geladen, den Grund hast Du ja schon genannt.

Gibt es denn keine Möglichkeit, zur Laufzeit Texturen zu laden ohne das die Anwendung blockiert?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Mär 15, 2008 23:16 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Ich habe das folgendermaßen gelöst (aber ich weiss nicht, wie das mit der Performance ist, ich habe den Code noch nicht effektiv testen können).
Im Thread wird die Textur aus der Datei geladen und erstmal in den Arbeitsspeicher kopiert, sodass dort die reinen RGBA oder wasauchimmer Pixeldaten vorliegen. Dies dürfte wegen dem Festplattenzugriff und eventuellen Dekodierungs- und Umwandlungsprozessen das Performancelastigste sein (hoffe ich zumindest :wink: ). Diese werden dann in ein kleines Objekt gekapselt an die Hauptanwendung weitergeleitet (mit einer eigenen Klasse, die von TList ableitet und diese Threadsafe macht). Die Hauptanwendung prüft nun in jedem Frame, ob irgendetwas in dieser Liste ist, was zu verarbeiten ist. Die Miniobjekte, in denen die Pixeldaten liegen, haben gleichzeitig auch eine Methode, die das tut, was zu tun ist (erspart mir verschiedene Listen für verschiedene Objekttypen wie Sound, Model oder was auch immer), im Falle der Texturen ist das das übertragen der Textur in den GRAM, ich verdeutliche das nochmal kurz.

Code:
  1.  
  2. [Thread                 ]               [Anwendung                      ]
  3. [Lädt Texturen aus Datei]    <====      [Gibt Dateinamen an Thread      ]
  4. [und holt die Pixeldaten]               [über Threadsafe TStringList    ]
  5. [in den RAM.            ]                    
  6.  
  7.           ||
  8.           ||
  9.           \/
  10.  
  11. ["Transporterobjekt"    ]               [Anwendung                      ]
  12. [Besteht aus:           ]               [Prüft jeden Frame auf neue     ]
  13. [- Behälter für die     ]               [Objekte in der Zwischenliste   ]
  14. [  Pixeldaten           ]               [Führt gegebenfalls deren       ]
  15. [- Methode, die die     ]               [Methode aus und gibt sie dann  ]
  16. [  Pixeldaten an OpenGL ]               [frei                           ]
  17. [  schickt              ]
  18.  
  19.           ||                               /\
  20.           ||                               ||
  21.           \/                               ||
  22.            
  23.                         [Zwischenliste          ]
  24.             ======>     [Klasse, die einen Stack]
  25.                         [simuliert, der Thread- ]
  26.                         [Safe arbeitet          ]
  27.  


Ich hoffe, ich konnte helfen.

Gruß Lord Horazont

_________________
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  
 Betreff des Beitrags:
BeitragVerfasst: So Mär 16, 2008 11:01 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Lord Horazont: Ja so in etwa ist das vollkommen richtig. Bzw geht auch irgendwo nicht anders. Alternativ zu der Liste kann man auch direkt mit Synchronize arbeiten. Dann werden die Methoden zum Erstellen der Texturen ausgeführt, wenn die Anwendung das nächste Mal Messages abarbeitet. So könnte es aber evtl. passieren, dass 2-3 Texturen zwischen den Frame erstellt werden (mehrere Threads). Mit einer Liste könntest du es dann steuern, dass nicht zu viele Texturen auf einmal erstellt werden. Maximal 2-3 pro Minute oder so.

Passi: Zu deinem Code im ersten Post. Du solltest auf keinen Fall Idle als Priorität benutzen. Denn auf einem Singlecore Prozessor dürfte das Laden der Textur durch einen dauerhaften Renderloop ausgebremmst werden. Denn Idle wird nur dann ausgeführt, wenn nicht gerendet wird was bei einem dauerhaften renderloop ja praktisch nicht passiert. Was ja auch nicht gewünscht wird. Du verstehst die Zwickmühle?

Auf Singlecore dürfest du im übrigen in jedem Fall merken, dass das Rendern ausbremst wird, denn die teilen sich eine CPU.

Im übrigen kann es auch sein, dass das uploaden der Texturdaten etwas zeit benötigt. Normal dauert das nicht lange außer es handelt sich um ein nicht so "gutes" Texturformat. Radeon 9600 und X800 hatten "Probleme" mit 24 Bit Texturen. Da wurde die intern wohl noch mal umgewandelt und das uploaden hat knapp 60 ms gedauert. Um Vergleich zu 1-2 ist das schon nen markanter Unterschied.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Mär 16, 2008 11:58 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Lossy eX hat geschrieben:
Lord Horazont: Ja so in etwa ist das vollkommen richtig. Bzw geht auch irgendwo nicht anders. Alternativ zu der Liste kann man auch direkt mit Synchronize arbeiten. Dann werden die Methoden zum Erstellen der Texturen ausgeführt, wenn die Anwendung das nächste Mal Messages abarbeitet. So könnte es aber evtl. passieren, dass 2-3 Texturen zwischen den Frame erstellt werden (mehrere Threads). Mit einer Liste könntest du es dann steuern, dass nicht zu viele Texturen auf einmal erstellt werden. Maximal 2-3 pro Minute oder so.

Genau deswegen wollte ich so eine Liste haben, höchstens fünf Texturen pro Frame, beziehungsweise, ich benutze die Threads eher beim Starten, weil ich einen flüssigen Ladebalken mit bewegungsfähigen Cursor nebenbei haben will, da dürftens dann auch ein wenig mehr sein.

Lossy eX hat geschrieben:
Im übrigen kann es auch sein, dass das uploaden der Texturdaten etwas zeit benötigt. Normal dauert das nicht lange außer es handelt sich um ein nicht so "gutes" Texturformat. Radeon 9600 und X800 hatten "Probleme" mit 24 Bit Texturen. Da wurde die intern wohl noch mal umgewandelt und das uploaden hat knapp 60 ms gedauert. Um Vergleich zu 1-2 ist das schon nen markanter Unterschied.

Das Umwandeln sollte dann auch noch im Thread ablaufen, zum beispiel bei SDL indem man die Surface auf ein entsprechendes Format blittet. Natürlich macht es wenig sinn schnell eine Palettierte 8-Bit Textur aus ner Datei zu laden wenn dann im kritischen Teil die Grafikkarte nen halbes Jahrhundert zum Umwandeln braucht.

Gruß Lord Horazont

_________________
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  
 Betreff des Beitrags:
BeitragVerfasst: So Mär 16, 2008 12:34 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Liste: Ist immer Geschmackssache. Kommt drauf an wo und wie man es benutzt. Wenn du den neuen Thread erst dann anwirfst wenn der Andere fertig ist, dann ist das vollkommen unkritisch. Dann ist das Starten und das Ende gut dosiert. Ich meinte es aber eher Zeitbasiert. Weil selbst 1 Textur bei jedem Frame dürfte ziemlich bremsen.
Zu viele Threads auf einmal anzuwerfen kommt auch nicht so gut. Bei einem Ladescreen sicher nicht so tragisch. Wobei man da auch nicht unbedingt Threads benötigen würde. Aber so was ist alles immer Geschmackssache. ;)

Umwandeln: Ja. Genau das ist ja das Problem was ich meinte. Das Umwandeln passierte innerhalb von glTexImage2D. Also innerhalb des Treiber. Das konnte man nicht auslagern. Und das war eine stink normale GL_RGB8 Texture. ;) Aber sonst ja. Es sollte grundsätzlich alles im Thread gemacht werden außer die Textur zu erstellen. Das geht ja nicht.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Mär 16, 2008 14:13 
Offline
DGL Member

Registriert: So Jul 17, 2005 12:59
Beiträge: 89
Hi,

erst mal vielen Dank für Eure ausführliche Antworten :)

Lossy eX: Ja verstehe ich. Hatte dem Texturloaderthread eigentlich auch nur eine niedrigere Priorität zugewiesen, weil ich dachte, dass sich damit mein ursprüngliches Problem lösen lässt. Aber hier war der Fehler ja, dass ich statt resume execute aufgerufen habe.

Gut, schade dass das Ganze nicht so einfach ist wie ich mir das vorgestellt habe..

Habt Ihr zu den einzelnen Schritten evtl. ein paar Stichworte? Also vor allem die beiden Punkte:
- Pixeldaten in den RAM schieben
- Pixeldaten aus dem RAM an OpenGL schicken

Hier weiß ich nicht so recht, wie ich das angehen muss.

Danke nochmals,
viele Grüße
Pascal


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Mär 16, 2008 18:04 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Du brauchst erstmal einen anderen Texturloader, z.B. sdl_image und ein wenig Handarbeit oder Lossy's glBitmap. Mit dem, den du gerade verwendest, hast du nur eine Funktion, die alle Schritte auf einmal macht. Bei der glBitmap z.B. kannst du erst die Datei laden (Schritt Pixeldaten in RAM, also LoadFromFile, LoadFromStream oder wasauchimmer) und dann die Textur erstellen (Pixeldaten aus RAM zur Graka, per Hand wäre das glTexImage2D).

Gruß Lord Horazont

_________________
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  
 Betreff des Beitrags:
BeitragVerfasst: Di Mär 18, 2008 00:29 
Offline
Guitar Hero
Benutzeravatar

Registriert: Do Sep 25, 2003 15:56
Beiträge: 7810
Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Wenn du standard Delphi-Windows-Programmierung betreibst, und SDL nicht eh schon benutzt, dann würde ich zu Lossys Loader raten. Der ist wirklich kein schlechtes Stück Code. Doku findest du im Wiki: Glbitmap_loader

_________________
Blog: kevin-fleischer.de und fbaingermany.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Mär 18, 2008 19:32 
Offline
DGL Member

Registriert: So Jul 17, 2005 12:59
Beiträge: 89
Alles klar,
vielen Dank für Eure Anworten.

Werd mir das demnächst mal zu Gemüte führen, scheint aber machbar zu sein ;)

Grüße
Pascal


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Mär 20, 2008 22:07 
Offline
DGL Member

Registriert: So Jul 17, 2005 12:59
Beiträge: 89
Hi,

so ich habe das Ganze nun mal extrem vereinfacht so implementiert, wie ich das verstanden habe.

Ich benutze nun die GLBitmap von Lossy. Die habe ich erst mal einfach so gelassen, wie sie ist. Mein Code sieht nun wie folgt aus:

Code:
  1.  
  2. var
  3.   Tex: TglBitmap2D;
  4.  
  5. implementation
  6.  
  7. procedure loadTexThread.execute();
  8. begin
  9.    tex := TglBitmap2D.Create('D:\test.jpg');
  10.    Terminate();
  11. end;
  12.  
  13. procedure TForm1.Button1Click(Sender: TObject);
  14. begin
  15.   texLoadThread.resume;
  16. end;
  17.  
  18. procedure TForm1.Button2Click(Sender: TObject);
  19. begin
  20.    tex.GenTexture(false);
  21. end;
  22.  
  23.  


Sollte das nicht schon ausreichen, um die Texturdaten im Thread zu laden, sie aber im Haupthread Hochzuladen?

Naja, jedenfalls funktioniert das leider nicht. Die Textur wird zwar geladen, ich kann sie binden und anzeigen, aber beim Klick auf Button2 lädt er erst mal wieder eine ganze Weile.

Muss ich die Übergabe zwangsweise in einem Objekt machen, oder wieso funktioniert das nicht? Oder hab ich etwas grunsätzlich falsch verstanden ;)?

Würd mich über Eure Ideen freuen,
viele Grüße
Pascal


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Mär 21, 2008 12:09 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Also so wie du das da gebaut hast musst du im laufenden Programm mit nem schönen haufen Problemen rechnen, da du das Objekt nicht Synchronisiert hast. Also der Thread könnte zu dem Zeitpunkt, wenn du schon versuchst, die GenTexture-Methode aufzurufen noch am Rumrechnen mit dem Objekt sein, was zu sehr verwirrenden Fehlern führen kann (ekelhafte Zugriffsverletzungen, nicht vollständige oder falsche Bilddaten...)

Wie groß ist deine Textur denn? Vielleicht lohnt es sich auch, die in kleinere Happen zu spalten, sodass du nicht so einen riesigen Klotz zur Graka schicken musst.

Gruß Lord Horazont

_________________
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  
 Betreff des Beitrags:
BeitragVerfasst: Sa Mär 22, 2008 15:16 
Offline
DGL Member

Registriert: So Jul 17, 2005 12:59
Beiträge: 89
Hi,

ok habe das nun Synchronisiert.
Mein eigentliches Problem löst sich dadurch aber leider nicht..

Es sind eigentlich viele kleinere Texturen die ich laden möchte, so dass das Hochladen einer Textur nicht sehr lange dauern dürfte. Aber es müssen eben viele (100-200) Texturen möglichst zeitgleich geladen werden. Und während dieses Ladevorgangs muss das Programm weiterhin möglichst flüssig arbeiten.

Ist mein Code oben denn semantisch korrekt, oder muss ich dort auch etwas ändern?

Vielen Dank für die Hilfe und schöne Ostern!

Grüße
Pascal


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Mär 22, 2008 18:03 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Yep, der code ist so ok.

Vielleicht solltest du überlegen, weshalb du so viele einzelne Texturen in so kurzer Zeit brauchst und ob du das irgendwie optimieren kannst.

Gruß Lord Horazont

_________________
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  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 31 Beiträge ]  Gehe zu Seite 1, 2, 3  Nächste
Foren-Übersicht » Programmierung » OpenGL


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 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.022s | 14 Queries | GZIP : On ]