Registriert: Mo Okt 15, 2007 18:30 Beiträge: 74 Wohnort: Berlin
Hallo zusammen,
ich möchte ohne OpenGL ein Bitmap im Speicher erzeugen und dieses dann in meine OpenGL Darstellung als Textur einbinden. Dabei möchte ich auch Alpha werte für jedes Pixel separat setzen können. Ich habe den Eindruck, das die TBitmap Komponente dafür nicht das richtige ist, weil neben den RGB werten von TColor der vierte Wert nur die Werte 0, 1 und 2 annehmen kann und bestimmt irgendwie die Auswahl der Farbe aus bestimmten Farbpaletten. Bei den nativen Windows Bitmaps weiß ich nicht weiter. Ich würde jetzt mal ein DIB (Device independent bitmap) erzeugen wollen, aber mit welchem API Aufruf mach ich das und wie?
In der Doku heißt es:
'CreateDIBSection' function creates a DIB that applications can write to directly...
Diese Funktion verlangt als ersten parameter ein handle auf einen Device context. Den habe ich ja eigentlich gar nicht, und mit den anderen Parametern kann ich auch nicht wirklich was anfangen.
'CreateDIBitmap' creates a compatible bitmap (DDB - Device dependent bitmap) from a DIB... scheint mir irgendwie auch nicht richtig.
Kann mir irgendjemand verraten wie ich mir ein Bitmap erzeuge, welches eine bestimmte Höhe, Breite hat und vollen RGBA support bietet?
Wenn ich dich richtig verstanden habe brauchst du garkeine Bitmap. Du kannst dir einfach so viel Speicher reservieren wie dein Bild brauchen wird.
Code:
var data:PByte;
data:=GetMem(width * height *4);
Den Speicher kannst du dann "auffüllen". Alternativ kannst du auch ein zweidimensionales Array nehmen, das ist vielleicht etwas einfacher. Danach kannst du den data-Pointer an OpenGL übergeben.
Registriert: Mo Okt 15, 2007 18:30 Beiträge: 74 Wohnort: Berlin
Hmm, ja wäre eine Möglichkeit, hab ich auch schon mal in betracht gezogen. Zusätzlich erzeuge ich das Bild aber noch in einem anderen Thread. In einer Critical section kopiere ich das Bild dann mittels BitBlt in die spätere Textur. Könnte mir vorstellen das das Kopieren eines Arrays von 1024*512*4 Byte die Performance eher negativ beeinflusst im Gegensatz zu einem Bitblock-Transfer. Daher wollte ich bei eigentlich bei einer Bitmap bleiben.
Ich verstehe dein Problem nicht. Du kannst einfach den Speicher allozieren, ihn in deinem Thread füllen und wenn dieser fertig ist die Daten im Hauptthread an OpenGL übergeben. Da muss man nichts kopieren.
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Windows Bitmaps (TBitmap) und Threads sind im übrigen ganz übel. Denn die GDI ist nicht Threadfähig. Sofern du das Bild nicht in auch irgendwo als richtiges Windows Bitmap benötigst würde ich davon auch abraten.
Ein weiterer Vorteil der Speichermethode ist der, dass du diesen Speicherbereich auch direkt an glTexImage übergeben kannst. Damit würdest du dir das Kopieren ganz sparen. Und Threadsicher ist es dadurch alle mal. Sofern die Methoden nichts falsches machen.
Mich würde dort aber bitte genau interessieren was du alles mit dem Bild machen willst?
Registriert: Mo Okt 15, 2007 18:30 Beiträge: 74 Wohnort: Berlin
Bezüglich der Threadsicherheit von TBitmap lässt sich sagen, dass das Canvas die Methoden Lock und Unlock besitzt. Damit lässt sich der Speicherbereich vor dem Zugriff durch mehrere Threads schützen.
Zur Speichermethode: Was passiert denn wenn der Arbeitsthread gerade das Array beschreibt, und der Mainthread davon lesen will? Außerdem habe ich beim Bitmap ja noch die möglichkeit Polygone zu zeichnen (wovon ich auch gebrauch mache). Bei der Speichermethode müsste ich mir noch entsprechende Zeichenroutinen schreiben, welche Stellen in dem Array denn nun von dem Polygon umschlossen sind und diese entsprechend färben.
Was will ich mit dem Bild machen:
Ich will es nur in OpenGL als Textur nutzen. Ich will den von einem Flugobjekt auf der Erde sichbaren bzw. überflogenen Bereich darstellen. Der noch nicht überflogene Bereich soll durch setzen des Alphawertes unsichtbar sein, die überflogenen Bereiche sollen Farbig, evtl. auch einen Alphawert zwischen 0 und 1 besitzen. Die erzeugte Textur soll dann über die Textur der Erde gelegt werden, entweder direkt auf einer Kugel, oder in 2D.
Registriert: Mo Okt 15, 2007 18:30 Beiträge: 74 Wohnort: Berlin
Da fällt mir noch was anderes zu ein: Ich nutze gluSphere, was kein Multitexturing unterstützt. Kann ich für eine Kugel mit glTexGen zusätzliche Koordinaten erzeugen, oder muss ich mir ein eigenes Primitive dafür erzeugen (ich glaub dafür gibts schon ein code-beispiel). Oder kann ich die Texturen besser vor dem 'Tapezieren' verblenden?
Wenn das jetzt zu umfangreich wird kann ich das auch gerne noch mal in einem separaten Thread posten.
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Threadsicherheit von TBitmap. Das Lock mag zwar die Canvas sperren, damit nicht 2 Stellen gleichzeitig darauf zugreifen. Allerdings rede ich nicht von irgendwelchen Speicherzugriffsverletzungen die dadurch entstehen können. Sondern davon, dass die GDI irgendwann einfach aufhört zu arbeiten. Klassisches Beispiel. Thread zeichnet ein zufälliges Viereck auf dem Formular. Das funktioniert so lange gut wie die Maus nicht über dem Fenster ist. Irgendwann ist sie drüber und dann kann es passieren, dass einfach keine Vierecke mehr gezeichnet werden. Ohne Fehler ohne irgendwas. Gleiches passiert auch, wenn man Bitmaps in einem Thread benutzt. Irgendwann funktionierts nicht mehr. Dabei spielt es auch keine Rolle ob du in Thread die Instanz 1 und in Thread B die Instanz 2 eines Bitmaps benutzt. Entsprechend gibt es keine Threadsicherheit.
Threads generell. Du musst natürlich auch dafür sorgend, dass sich 2 Stellen nicht in die Quere kommen. Das ist deine Aufgabe als Entwickler. Denn das Programm kann nicht wissen was gewollt ist und was nicht. Was dabei passiert hängt vom genauen Timing und dem was du tust ab. Wenn du zum Beispiel eine Stelle gerade mit Daten befüllst und diese bereits nach OpenGL überträgst, dann wird wahrscheinlich nur die Hälfte in OpenGL ankommen. Die anderen Speicherstellen sind Undefiniert. Wenn du aber gerade dabei bist den Speicher in der Größe zu erweitern, dann kanns gut Zugriffsverletzungen geben. Es kann aber schlicht nichts passieren. Wenn du hinten dem Speicher etwas reinschreibst und vorne ausließt dann kann auch alles glatt gehen.
Kann das sein, dass du eine Art Nebel des Krieges (Fog of War) machen willst? Da könntest du eventuell auch eine niedrig aufgelöstere Textur benutzen. Durch die Glättung des Texturfilters hättest du automatisch weichere Kanten. Dann würde auch das Setzen eines einzelnen Pixels dafür sorgen, dass ein größerer Bereich aufgedeckt würde. Die Menge an Daten die gezeichnet und übertragen werden müssten wären verschwindend gering. Obendrein würdest du Speicher sparen und müsstest dich auch nicht mit den Threads rumschlagen.
In solch einem speziellen Fall (Nebel des Krieges) könntest du eventuell auch ganz ohne clientside Bitmaps auskommen. Ich hatte mal Testweise mit FBOs rumgespielt und so eine Art Malfuktion erstellt. Damit konnte ich mit der Maus einen Alphakanal malen der die Sichtbarkeit zwischen zwei Texturen geregelt hatte. Das Ganze war um ein Vielfaches schneller als man das je auf der CPU hätte hinbekommen. Und ich hatte sehr schöne weiche Übergange, musste nichts selber berechnen und auch nichts übertragen. Weil ja bereits alles auf der Grafikkarte war.
PS: Was gluSphere angeht solltest du entweder etwas eigenes benutzen oder aber im zweifel wäre es auch mit Shadern möglich die TexturKoordinaten auf die anderen Texture mit zu übertragen. Allerdings gluSphere würde ich da wohl generell eher nicht nehmen. [edit] Solltest du weitergehende Fragen dazu haben solltest du das wohl in einem extra Thema machen.
Registriert: Mo Okt 15, 2007 18:30 Beiträge: 74 Wohnort: Berlin
Der Nebenthread generiert permanent Daten die in einen gemeinsam genutzten Buffer geschrieben werden. Der Hauptthread holt diese gelegentlich ab (ca. 20-30 mal pro sekunde). Auf den Buffer wird nur geschützt zugegriffen. Während sich im Buffer Datensätze von diskreten Simulationsschritten befinden, wird das Bitmap gewissermaßen nur erweitert, heißt weitere überschrittene Bereiche gezeichnet. Es ist eigentlich nie so richtig fertig. Jedesmal wenn der Hauptthread wieder die im Buffer angesammelten Datensätze abholt, muss er auch eine Kopie vom aktualisierten Bitmap machen. Die Datensätze werden gespeichert und ihr speicher wieder freigegeben. Der aktuellste Datensatz wird auf dem Bildschirm ausgegeben, ebenso wie das aktuelle Bild.
Vorteil: Der Arbeitsthread ist von der Visualisierung weitestgehend entkoppelt. Er muss nicht auf die langsamere Darstellung warten, gleichwohl die Visualisierung noch flüssig abläuft.
Aber nochmal zu meiner Frage: Das klassische Windows-Bitmap ist wohl nicht zu empfehlen, eben weil keine Threadsicherheit besteht. TBitmap wäre mir am liebsten, weil wohl durch Lock/unlock threadsicher und routinen zum Zeichnen vorhanden sind. Problem: Weiß irgend jemand ob man im TBitmap einen Alphakanal angeben kann?
Kapsel dir den Ansatz von oben doch einfach in einer kleinen Klasse und sorg selbst für das Locken/Unlocken. -> Du hast genau das, was du willst dann und nicht mehr. Kein weiterer Overhead, den z.B. TBitmap mitbringt, keine Sorgen um das nötige Format.
Registriert: Mo Okt 15, 2007 18:30 Beiträge: 74 Wohnort: Berlin
Zitat:
...die GDI irgendwann einfach aufhört zu arbeiten. ... Irgendwann funktionierts nicht mehr. Dabei spielt es auch keine Rolle ob du in Thread die Instanz 1 und in Thread B die Instanz 2 eines Bitmaps benutzt. Entsprechend gibt es keine Threadsicherheit.
Danke, dann vergess ich die sache mit den bitmaps und machs über das Array.
Registriert: Mo Okt 15, 2007 18:30 Beiträge: 74 Wohnort: Berlin
Zitat:
Kapsel dir den Ansatz von oben doch einfach in einer kleinen Klasse und sorg selbst für das Locken/Unlocken. Smile -> Du hast genau das, was du willst dann und nicht mehr. Kein weiterer Overhead, den z.B. TBitmap mitbringt, keine Sorgen um das nötige Format.
Mach ich, hatte nur gehofft, dass ich die GDI routinen von Bitmap bzw. TBitmap nutzen kann.
Registriert: Fr Jan 04, 2008 21:29 Beiträge: 419 Wohnort: Lübeck
die Zugriffssicherheit kannst du erreichen, in dem du einen Quadtree verwendest um zu zeichnen und zu lesen. Der Bereich in dem du liest bekommt ein read-flag und der bereich in dem du schreibst bekommt ein write-flag. Ein Thread darf nur mit dem Bereich arbeiten, wenn ein none-flag vorliegt, dass nach dem ausführen des Arbeitsauftrages von beiden Threads gesetzt werden kann. so arbeitest du 1. nur veränderte Teile deiner Daten ab und 2. bekommst du keine Zugriffsverletzungen, da nur fertig gezeichnete Bereiche gelesen werden dürfen.
Zum zeichenn selbst würde ich dir ein FBO und 2Dtexturen im RGBA format ans herzlegen. Da du die Daten ja nach deiner Beschreibeung nur im Speicher brauchst ist es blödsinnig sich mit einer Fileformat-Komponente herumzuschlagen, die meiner Meinung nach eh nichts taugt im Echtzeit-Bereich. Die einzelnen Zeichenbereiche des Quadtrees kannst du dann ja mit fixer Größe festlegen.
Am besten wäre es, wenn dein Lesethread wartet mit der Datenübertragung, bis der Bereich den er übertragen soll wieder frei ist, oder ihn sich merkt und erstmal überspringt, bis er wieder frei ist.
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
hefekuchen hat geschrieben:
Danke, dann vergess ich die sache mit den bitmaps und machs über das Array.
Also Arrays würde ich zur Bildverarbeitung auch nicht benutzen wollen. Besonders wenn du ein dynamisches 2D Array benutzt, dann kannst du deine Daten nicht an einem Stück hochladen. Bzw die Zugriffe auf die Elemente würden auch teurer werden als wie wenn man die Daten an einem Stück im Speicher hätte. Ich mache das meistens immer so, dass ich einen kompletten Speicherbereich mit GetMem erstelle und ein Array mit der anzahl der Zeilen erstelle. In dem Array trage ich nach dem Erstellen des Speichers die Scanlines ein. Also den Pointer auf das erste Pixel einer Zeile.
Wobei ich wenn möglich die Darstellung auf die GPU verlagern würde. Also selbst, wenn du das Bild dauerhaft aktualisieren müsstest wäre das kein Ding. Du müsstest nur mit FrameBufferObjects immer wieder dafür sorgen, dass die Veränderungen in deiner Textur verrechnet würden. Und dann hättest du hardwarebeschleunigte Blendeffekte und alles.
hefekuchen hat geschrieben:
Auf den Buffer wird nur geschützt zugegriffen.
Ich vermute mal Critical Section. Achte bitte darauf nicht zu viel zu synchronisieren. Der Sinn von Multithreading ist so wenig wie möglich zu synchronisieren. Denn das Synchronisieren benötigt auch immer Zeit. Bzw muss einer immer mal wieder warten.
Kleines Beispiel. Sagen wir mal du hast eine Liste als Buffer in der du deine Daten sammelst. Jedes mal wenn du einen Eintrag in die Liste packen möchtest müsstest du mit der Section die Liste blockieren. Wenn der Hauptthread auf die Liste zugreifen wollte müsste die Liste mit der gleichen Section blockiert werden. Entsprechend dürfte die Liste sehr sehr oft gelockt sein. Das so zu realisieren, dass solch eine Liste nicht dauerhaft gelockt ist ist definitiv nicht einfach. Könnte mir aber gut vorstellen, dass es noch mal gut was bringt. Es wäre ja auch möglich beim Zugriff aus dem Hauptthread diese Liste einfach gegen eine Leere auszutauschen. Wobei ich da aber anstelle einer Liste lieber eine verkette Liste benutzen würde. Wenn man die Werte in der passenden Reihenfolge austauscht könnte so etwas sogar ganz ohne Locking gehen.
Mitglieder in diesem Forum: 0 Mitglieder und 7 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.