# java2D/jogl interoperability



## muckelzwerg (9. Mrz 2011)

Hey, kennt sich zu dem Thema jemand aus.
Ich stoße da auf fünf Jahre alte Demos, Blogeinträge und irgendwelche Forenlinks die nicht mehr funktionieren.
Grundsätzlich wüsste ich ganz gern, was denn da der aktuellste Stand ist und wie man da zur Zeit rangehen sollte.
In meinem Fall geht es um OpenGL-Rendering von Swing-Komponenten und Swing Overlays in jogl-Szenen.
Klar, ein BufferedImage als Textur für eine Fläche zu verwenden ist naheliegend. Aber das ist ja wohl nicht alles.


----------



## Runtime (9. Mrz 2011)

Agile2D Home


----------



## muckelzwerg (9. Mrz 2011)

Ja, darüber bin ich auch gestolpert. Kannst Du dazu was sagen? Da wird der JFrame ersetzt und dessen Rendering auf Jogl umgebogen, wenn ich das richtig verstehe.
Dieser Spielkram aus den Jogl-Demos mit den Dropshadows basiert aber auf dem Textrenderer in einer "normalen" jogl-szene.
Agile ist dann also der Schalter für HardwareRendering, bietet aber erstmal keine neue "optische" Funkionalität?


----------



## Marco13 (9. Mrz 2011)

Es gibt Anzeichen dafür, dass Agile2D hoffnungslos veraltet ist: Stand 2003, Anbindung an GL4Java (in Memoriam :autsch: ...). Das ist (oder war) aber ohnehin nicht viel mehr als ein OpenGL-beschleunigtes "Graphics". Man kann davon ausgehen, dass mit neueren JVMs der Geschwindigkeitsvorteil, der dort beschrieben ist, nicht mehr so dramatisch ist (oder sich vielleicht(!) sogar umgekehrt hat!) - schließlich verwenden die neueren Java-Versionen auch OpenGL, und zwar nicht "aufgesetzt", sondern eher "von Grund auf". 

Das hat aber auch nichts mit "Swing-Overlays in JOGL-Szenen" zu tun. Dazu bist du vermutlich auch über Swogl gestolpert. Zugegeben, es ist auch nur eine "Beta", und sieht auf den ersten Blick fast genauso tot aus wie Agile2D  aber das Gegenteil ist der Fall: Ich bin da (anläßlich dieses Threads) wieder fleißig am basteln. (Noch) nicht spezifisch-zielgerichtet für Swogl an sich: Ich habe eher elementar angesetzt, und arbeite 1. an einem Renderer, der einigermaßen allgemein ist (und sowohl mit JOGL als auch mit LWJGL funktioniert!), und 2. an einer Bibliothek, mit der man Swing-Components "fernsteuern" kann - früher oder später werde ich das hoffentlich zusammenwerfen können, und daraus hoffentlich Swogl 2.0 (version 0.0.1  ) entstehen. 

Alternativen? Von Java selbst gab es Dinge wie Wonderland (jetzt Open source 3D virtual collaboration toolkit | Open Wonderland ) oder Project Looking Glass - Wikipedia, the free encyclopedia - vermutlich hast du sie schon gefunden, und das waren die Teil von dem "alten Zeug" das du erwähnt hast...


----------



## muckelzwerg (10. Mrz 2011)

Ich habe eine Anwendung, bei der 2D-Menüs "übereinander" gestapelt werden und Echtzeitvisualisierung machen. (gestapelt wie bei den normalen Javapanes quasi)
Da hätte ich ganz gerne ein hardwarebeschleunigtes Rendering. 
Ein Teil der Menüs arbeitet mit eigenen Widgets, die in LUA entwickelt werden und auch komplett unabhängig von den gewöhnlichen Widgetklassen mit Events befeuert werden.
Java2D taucht dort bisher nur auf, um die Widgets zu zeichnen. (Wenn ich eine bessere Grafikbibliothek finde, werde ich das wohl auch ersetzen.)
Ansonsten brauche ich Java2D eigentlich "nur", damit ich nicht jeden Schmodder wie Menüleisten etc. selbst bauen muss.
Das ganze in eine OpenGL-Kontext zu bringen, soll in erster Linie Geschwindigkeitsvorteile bieten.
In zweiter Instanz hoffe ich, dort dann leichter mit Shadern arbeiten zu können. 
Alle Menüs werden in BufferedImages gezeichnet. Die kann ich auch "von Hand" in jogl als Textur verwenden. 

Für mich stellt sich also überwiegend die Frage "Was geht da noch?". Sobald ich ein Menü verschiebe oder perspektivisch verzerrt darstelle, muss ich für Interaktionen wieder das ganze Picking selbst berechnen. Das ist nicht die Welt, aber wenn es eine Umgebung gäbe, die mir sowas schenkt, wäre das z.B. hilfreich. Swogl kann das, wie es aussieht?


Vielleicht noch eine andere Frage, die ein bisschen abweicht. (Du scheinst Dich ja gut auszukennen.  )
Nehmen wir an, ich zeichne meine Menüs und lege sie dann als Textur auf eine Fläche in der jogl-szene und gebe an OpenGL ab.
Was wäre der schnellste bzw. effizienteste Weg die Texturen zu erzeugen?
Da ich eigene Widgets zeichne und mit Events versorge, brauche ich die ganze Swing-Ausführung eigentlich nur noch für die Standardwidgets aus Java.
Da komme ich dann wohl nicht drumrum. Gibt es da andere Bibliotheken, die sich empfehlen würden, oder macht es grundsätzlich keinen Sinn, Swing rauszuwerfen und mit was anderem zu zeichnen?


----------



## Marco13 (10. Mrz 2011)

Ob ich wirklich verstanden habe, was du vorhast und worum es geht, weiß ich nicht genau. Aber ganz allgemein: Man kann davon ausgehen, dass jeder Beschleunigungsversuch (wie Swing-Components in Texturen zeichnen, um sie dann von JOGL auf den Bildschirm bringen zu lassen) langsamer sein wird, als wenn Swing das direkt macht. Die Leute von Sun sind nicht blöd, und die haben Mittel und Möglichkeiten, dort Hardwarebeschleunigung zu nutzen, die man als reiner Anwender von Swing definitiv nicht hat. 

Die perspektivische (und nicht nur die  ) Verzerrung ist genau das, was von Swogl schon abgedeckt wird: Man bekommt die Texturkoordinaten des angeklickten Punktes, und die werden zurückgerechnet in die Koordinaten der Component, die auf dieser Textur zu sehen ist. Aber wie gesagt: Das alles in einer "Beta", und bisher nur in einen ziemlich spezifischen Kontext. Hauptziel des Refactorings (eher: Rewrites) ist es, das flexibler zu machen: Bisher kann man SwoglComponents in einem SwoglContainer darstellen - der enthält den GLCanvas, und die "Szene" besteht aus den Components. _Eigene_ Szenenelemente könnte man nur mit Hacks und Krämpfen einfügen. Das Ziel ist darum, eine Möglichkeit zu bieten, SwoglComponents möglichst leicht direkt in schon existierende Anwendungen/Szenen einbauen zu können. Aber das ist noch ein bißchen Arbeit.


_Was wäre der schnellste bzw. effizienteste Weg die Texturen zu erzeugen?_

Man wählt die beste Religion und betet zu dem geeignetsten Gott  Mal im ernst: Das ist schwer zu sagen. Im Moment gehe ich davon aus, dass in irgendeine Form von BufferedImage reingezeichnet wird. Bei einem normalen INT_ARGB oder so liegt schon alles in einem int-Array, d.h. das sollte schon recht flott sein. Als Alternative dazu habe ich mal ein DirectBufferedImage implementiert, mit dem man theoretisch direkt in den OpenGL-Speicher reinmalen kann, aber dazu noch keine dedizierten Geschwindigkeitsvergleiche gemacht.


----------



## muckelzwerg (10. Mrz 2011)

Ich hab bei Swing einfach das Gefühl, da laufen im Hintergrund diverse Threads, die lauter Zeug machen, das ich eigentlich gar nicht mehr brauche.
Wie ist das denn mit den Anzeigeschleifen? Du hast eine "gameloop" in Jogl, mit der die Texturen gezeichnet werden. Aber die Swinginhalte verändern sich wieder nur mit dem Swing-Runner.
Damit ist es aber furchtbar Dinge wie z.B. Positionsvorherbestimmung (Kalmanfilter und solche Sachen) zu berechnen.
Ich hab einige Grafikelemente, die ich komplett selbst zeichne. Im Prinzip ist das auch nur Maler-Algorithmus auf ein einzelnes Bufferedimage. 
Das Image ist erstmal unabhängig von Swing und müsste dann entsprechend der Jogl--FPS (und natürlich der Berechnungsgeschwindigkeit der Bilder) angezeigt werden können.
Wenn die Swing"Flächen" jetzt zusätzlich da reinkommen und entkoppelt über Swing aktualisiert werden, dann wäre das wohl noch in Ordnung, aber auch nicht richtig toll.
Oder hast Du da was gebastelt, das die repaint()-rate auf die jogl-fps anhebt?

Was hast Du bei dem DirectBufferImage gemacht?


----------



## Marco13 (10. Mrz 2011)

Hm. So ganz kann ich einige der jetzt eingeworfenen Begriffe nicht einordnen ???:L

Natürlich laufen bei Swing mehrere Threads, aber die wird man nicht "abschaffen" - sobald man einen JFrame aufmacht, ist im Hintergrund die Swing-Maschine am Arbeiten, und da wird man auch nichts dran ändern können. Und muss man auch nicht. Die Threads laufen ja nicht zum Spaß. In erster Linie ist das der EDT (Event-Dispatch-Thread), und um irgendeinen Thread, der Benutzereingaben verwaltet, wird man kaum drumrumkommen.

Bei Swogl ist es ganz grob so, dass man repaint-Events mitbekommt, und daraufhin (im JOGL-Thread) ggf. Texturen aktualisiert werden. Die repaint-Events kommen von EDT. Was das jetzt mit einem Kalmanfilter zu tun hat, und wozu du überhaupt Swing brauchst, wenn du die Sachen sowieso nur selbst in eine Textur zeichnest, ist mir nicht klar....

Das DirectBufferedImage ist "einfach" eine implementierung von einem BufferedImage, dem man einen beliebigen ByteBuffer (d.h. IntBuffer) für die Speicherung der Daten unterschieben kann. Das kann auch ein DirectByteBuffer sein - und bei Swogl dann auch einer, der direkt auf den gemappten Grafikkartenspeicher zeigt.


----------



## muckelzwerg (10. Mrz 2011)

Es ist so, dass ich einige Widgets verwende, die nicht aus Swing, sondern von mir selbst mit Events befüllt und verarbeitet werden.
Da ich dort z.B. auf schnelle Sensormessungen reagiere, ist das Swingmodell mit "on-Demand-Rendering" nicht gerade optimal.
Da möchte ich natürlich lieber eine saubere Schleife haben und sagen können "JETZT wird gezeichnet".

Für Filter etc. vielleicht ein Beispiel. Du kennst bestimmt die vielen Multitouch-Tabletops, die in den letzten Jahren überall entwickelt wurden.
Wenn Du auf so einem Gerät mit den Fingern etwas verschiebst, dann hast Du ein "lag". Das lässt sich auch nicht durch schnelle Software verhindern, weil Du mit 60Hz Anzeigen ausgebremst wirst.
Für sowas kann man z.B. Filter verwenden und aus den Messungen zwischen zwei Renderingpasses die wahrscheinlichste Position bestimmen. Das geht aber deutlich besser, wenn man eine einigermaßen konsistente Rendereingschleife hat.

Swing brauche ich für meine eigenen Widgets grundsätzlich gar nicht. Ich benutze Java2D, um sie zu zeichnen. Da könnte ich auch etwas anderes verwenden. Aber da ich auch noch ein paar richtige Swing-Widgets benutze, liegt es nahe, erstmal keine weitere Zeichenbibliothek einzubauen.
Zusätzlich bekomme ich von Swing auch eine ganze Menge von Komponenten, Layouts etc. geschenkt. Das müsste ich sonst alles selbst basteln. Dafür "brauche" ich Swing.


----------



## Marco13 (10. Mrz 2011)

OK... es geht also darum, dass du z.B (nur als Beispiel) 100 mal pro Sekunde eine Grafik aktualisieren willst - z.B. direkt in ein BufferedImage zeichen, und zwar so, dass das _sofort_ auf dem Bildschirm erscheint. Und das funktioniert nicht, weil Swing aus Prinzip nicht so oft hintereinander zeichnet?! Das Zeichnen in ein BufferedImage und das anzeigen dessen mit OpenGL hat mit Swing und seinen Threads afaik erstmal nicht sooo viel zu tun, aber ob und inwieweit dann tatsächlich irgendwelche Anhängigkeiten bestehen, kann man so aus dem Stegreif kaum sagen...


----------



## muckelzwerg (10. Mrz 2011)

In erster Linie geht es um die "Echtzeit", also darum, dass ich einigermaßen genau weiß, wann gezeichnet wird und dass eben in einer "gleichmäßigen" Schleife gezeichnet wird.
Ich habe mehrere Ebenen auf denen aktualisiert wird. Zuerst habe ich eine sehr hochfrequente Aktualisierung bei den Ereignissen und Sensormessungen etc.
Man kann die Sensordaten zwar puffern, aber sie sollen ja nicht zu stark veralten. 
Etwas langsamer arbeitet dann die Aktualisierung der Darstellung. Und da will man natürlich mal Dinge wie Framesynchronisation etc. machen. Oder z.B. Statistiken basteln, wie lange es so "ungefähr" dauert, bis das Bild wirklich angezeigt wird, um Forwärtsberechnungen zu verbessern. Für sowas ist das Swing-Rendering eklig. 
Da weiß ich ja nie genau, ob und wann und vor allem wodurch ein Neuzeichnen ausgelöst wird.

Deswegen (und weil Swing bestimmte Widgets nicht bieten kann) berechne ich einige Menüs selbst (auch deren Events) und zeichne sie (momentan mit Java2D) in ein BufferedImage.
Aktuell läuft die Anwendung gerade nicht mit jogl, also wird dieses BufferedImage letztlich doch wieder über einen JFrame gezeichnet.
Das ist aber nur Nebensache, der Inhalt ist von Swing unabhängig. Meine Grafikklassen leiten auch keine Components ab, oder sowas.
Ich werde also letztlich dieses BufferedImage "so schnell wie möglich" auf eine OpenGL Textur rendern. Da schau ich auf jeden Fall mal nach dem "DirectBufferImage". Danke.

Da ich aber nicht alles von Hand machen möchte und auf sowas wie "Gaming-UI" in diesem Fall nicht so sehr vertraue (ist halt doch eher eine Desktop-Anwendung, wo man dann plötzlich "mal schnell" einen Kalender, oder XZYChooser oder sonstwas braucht)
will ich diese selbstverwaltete UI mit Swing kombinieren.

Und wie genau diese Kombination ablaufen soll, darüber bin ich mir noch nicht klar. Wenn ich Swing-Menüs als "langsame Texturen" in die gleiche Umgebung einfügen kann, dann wäre das schonmal ganz in Ordnung.
Etwas "symbiotischer" wäre aber gut. So dass ich zum Beispiel in einer eigenen "schnellen" Visualisierung mit "rechter Maustaste" einen SwingDialog öffnen kann und irgendwas benutze, was ich nicht aufwändig nachprogrammieren will.
Für sowas halte ich bisher eine Mischung über die "Polygone" am besten. Also ein Modell, bei dem ich mich selbst um das Platzieren und Arrangieren von eigenen Oberflächen und Swingoberflächen kümmern muss. Aus jeder Oberfläche wird dann letztlich eine Textur für eine Oberfläche in jogl. Alles wo Swing reingemalt wird, ist dann halt etwas langsamer, das sollte aber nicht das Problem sein.

Soweit gut. Allerdings ist es dann nicht möglich, z.B. ein eingenes "schnelles" Grafikelement in ein bspw. JPanel einzufügen.
Da muss ich mich um das Übereinanderlegen und logische Verknüpfungen selbst kümmern.
Supergut wäre es, wenn ich trotzdem die Container und Layoutmanager benutzen könnte. 
Dafür müsste dann so etwas wie ein "ExternalPanel" existieren.
Dann könnte ich eine gewöhliche Swing-UI bauen und irgendwo ein solches Panel für z.B "Sensorvisualisierung" einbauen.
Dieses Panel würde bei "repaint()" überhaupt nicht reagieren und unabhängig von Swing in ein BufferedImage zeichnen, wenn die "schnelle" Schleife das ansagt.
Das Swingmenü wäre an dieser Stelle dann "leer" und in der jogl-szene würde dann die passende Textur drübergelegt oder sogar direkt per Offset an die jeweilige Stelle kopiert.
Dennoch könnte man auf Größenänderungen usw. noch reagieren. 

Ungefähr klar, was ich meine?


----------



## Marco13 (10. Mrz 2011)

So ungefähr... Jetzt noch die spanndene Frage, warum das in 3D sein soll. Nach dem bisher beschriebenen klingt das so, als wäre eine reine 2D-Component dafür auch OK. Das wäre dann ein GLCanvas, wo einfach mit (dem etwas veralteten, aber AFAIK rattig schnellen) glWritePixels die Daten reingemalt werden könnten, die aus dem BufferedImage kommen - ggf. könnte man dann eben mit dem DirectBufferedImage (hatte ich mal hier gepostet: http://www.java-forum.org/codeschnipsel-u-projekte/105991-directbufferedimage.html ) auch direkt in ein PBO schreiben. Da würde dann jedes TextureMapping wegfallen, und schneller ginge es wohl kaum...

Das allgemeine "Problem", dass bei Swing darin besteht, dass man nicht weiß, wann und wie neugezeichnet wird, ist nachvollziehbar - aber wie kritisch das sein kann ...? (Kein Mensch kann die Information schneller verarbeiten, als Swing sie zeichnen kann, also... ich weiß nicht, welcher Aufwand da für wie viele gesparte Millisekunden gerechtfertigt ist...)


----------



## muckelzwerg (10. Mrz 2011)

Mir geht es ja auch um ein GLCanvas. "3D" ist nützlich, weil es in der Anwendung logisch übereinanderliegende Layer gibt.
In einer OpenGL-Szene kann ich die sehr angenehm auf verschiedene Flächen übertragen und zum Beispiel dazwischen blenden.
Das lässt sich natürlich auch mit einem "plattgedrückten" Stapel und in 2D machen. Aber einige der Sensoren sind 3D-Tracker.
(IR, TOF, Kinect ...)
Da ist es sehr angenehm, wenn man auch drei Dimensionen zum Arbeiten zur Verfügung hat, ohne dass man die für die Darstellung immer zusammenquetschen oder Umrechnen muss.

Genau an die Geschichte möglichst direkt in PBOs, FBOs zu schreiben hatte ich gedacht.

Bei der Geschwindigkeit geht es ja nicht um schnell veränderliche Zahlen oder sowas. Bei Drag&Drop bekommt man mit 60Hz zwangsläufig eine Verschiebung. 
Wenn die Sensordaten verrechnet werden, sind sie bereits alt. Ok, damit kann man umgehen. Aber wenn sie gezeichnet werden, dann sind sie noch älter. Damit also ein Objekt (möglichst) dort liegt, wo bspw. der Marker oder Finger liegt, berechnet man voraus.
Und das wird ungleich schwieriger, weil man bei Swing halt so gar nicht weiß, ob und wann gezeichnet wird.
Selbst bei einer langsamen "Gameloop" weiß ich immerhin, dass ein Bild abgeschickt wurde, wenn ich einmal durchgelaufen bin.
Mit asynchronem Swing nebendran, weiß ich noch nichtmal wieviele Bilder überhaupt erzeugt wurden.
Das muss ich dann umständlich aus dem Swing-Thread rausbasteln und wirklich toll ist das nicht.

Eine andere Variante ist mir grad noch eingefallen. Kennst Du Dich mit GLJpanel aus? Da hat man für jedes Panel einen eigenen OpenGL-Kontext? Das klingt für mich irgendwie umständlich und nicht gerade optimal, wenn ich z.B. 20 Schaltflächen hätte, die ich mit solchen Panels zeichnen will.
Ansonsten wäre das eigentlich ganz cool. Als Komponente in Swing integriert und ich könnte dort dann direkt in eine Textur zeichnen.
(Dann hätte ich natürlich keine 3D-Funktionen für die ganze Anwendung mehr.)


----------



## Marco13 (10. Mrz 2011)

OK, das ganze also in der Hoffnung, dass etwas, was main im display() eines GLEventListeners macht, häufiger und schneller auf den Bildschirm kommt, als per Swing. Davon kann man wohl ausgehen, aber in anbetracht des möglichen Aufwandes, der mit so einer Umsetzung verbunden sein könnte, sollte man das vielleicht nochmal (ggf. an einem Mini/Testbeispiel und mit ein bißchen wühlen im JOGL-Quellcode) verifizieren. Sowas wie vsync o.ä. könnten da unerwarete Auswirkungen haben, und die Möglichkeiten dort einzugreifen könnten sehr begrenzt sein.

Der Hautpunterschied zwischen GLJPanel und und GLCanvas _aus Anwendersicht_ ist, dass das GLJPanel lightweight ist - aber intern sind die Unterschiede offenbar nicht ganz unerheblich. Was für mich der Killer war: Bei jeder Größenänderung wird der GL-Context des JPanels neu erstellt (weil es intern PBuffers verwendet) - d.h. alle einmal auf die Grafikkarte geschaufelten Daten sind dann futsch. (Für Details dazu ... warte bis Fancy sich hier meldet). Abgesehen davon ist es insgesamt wohl auch deutlich langsamer. In den letzten JOGL-Versionen, die ich getestet hatte, hat es auch mit einem GL3-Profile nicht funktioniert, aber das sollte nur eine Kleinigkeit gewesen sein, und ist inzwischen vielleicht schon gefixt. Insgesamt ist ein GLJPanel wohl für einige Anwendungen OK, kann aber u.U. einige Schwächen haben, die - je nach Anwendung - unterschiedlich schwer wiegen können...


----------



## muckelzwerg (10. Mrz 2011)

Nicht nur wegen der Geschwindigkeit, aber auch. Es ist halt auch eine viel angenehmere Struktur, wenn ich Daten einsammle, zeichne, und wieder von vorne anfange und nicht Swing sage "hey, ich hab was geändert, vielleicht zeichnest Du demnächst mal neu, ja? bitte? ..."
Einige 3D-Funktionen werden auch hilfreich sein und Shader sowieso.

Na dann spar ich mir das mit dem GLJpanel sowieso. Das wäre nur die halbe Miete und vermutlich kaum weniger Stress in der Organisation.
Auf jeden Fall mal vielen Dank für die Infos! Das hat mich gleich ein Stück weitergebracht.


----------



## Friedhelm (18. Mrz 2011)

@Marco13



> Das DirectBufferedImage ist "einfach" eine implementierung von einem BufferedImage, dem man einen beliebigen ByteBuffer (d.h. IntBuffer)
> für die Speicherung der Daten unterschieben kann. Das kann auch ein DirectByteBuffer sein - und bei Swogl dann auch einer, der direkt
> auf den gemappten Grafikkartenspeicher zeigt.



Kannst Du mir ein Codeschnipsel dazu zur Verfügung stellen?

Würde gerne die Kinect-Bilder (BufferedImage) in JOGL zeichnen lassen anstatt in der JPanel paint() Methode. Da würde so ein DirectBufferedImage perfekt passen denke ich


----------



## muckelzwerg (18. Mrz 2011)

Hat er doch schon gemacht.
http://www.java-forum.org/codeschnipsel-u-projekte/105991-directbufferedimage.html


----------



## Marco13 (18. Mrz 2011)

Ich habe mal einen Geschwindikgeitsvergleich zwischen BufferedImage und DirectBufferedImage gemacht: Das DirectBufferedImage ist bei bestimmten Operationen um einige Größenordnungen _langsamer_. Insbesondere wenn man ein BufferedImage in ein DirectBufferedImage reinzeichnen will. Wenn man ein BufferedImage in ein anderes BufferedImage reinzeichnet, passiert intern unglaublich viel "Magie" (hab' da mal in Sun's Quellcode gewühlt... Kaum zu glauben, dass die wissen, was sie da tun :shock: ). Insbesondere werden die Daten dort praktisch direkt als Block von einem BI ins andere BI rüberkopiert. Wenn man in ein DirectBufferedImage zeichnet, geht das natürlich nicht, und er zeichnet das Bild quasi "pixelweise"  

Je nach Anwendungsfall könnte es also schneller sein, statt des DirectBufferedImages ein normales BufferedImage (TYPE_INT_*) zu nehmen, und den int[]-Array, der die Daten enthält, bei Bedarf direkt nach OpenGL rüberzuschaufeln. So ein Kopieren eines Blockes kann schneller sein, als wenn man alle intern-versteckten Optimierungen durch einen eigenen Bildtyp aushebelt.

Ich werde nochmal Vergleiche machen, wie die Geschwindigkeit sich unterscheidet bei anderen Dingen, z.B. Text oder Shape2Ds zeichnen - DORT können solche Optimierungen eigentlich nicht greifen, vielleicht erreicht man da mit dem DirectBufferedImage eine vergleichbare Geschwindigkeit.


----------



## muckelzwerg (18. Mrz 2011)

Das versteh ich erstmal nicht.  Was geht nicht blockweise? Wo zeichnest Du "pixelweise"?
Du verwendest zum Zeichnen doch das SunGraphics2D Objekt? Und das schiebt den ganzen Schmodder in die RenderQueue.
Wieso macht das einen Zeitunterschied?
Ich denke, es geht nur darum, dass man den Inhalt des BufferedImages nicht mehr in die OpenGL-Textur kopieren muss?


----------



## Friedhelm (18. Mrz 2011)

Marco13 hat gesagt.:


> Je nach Anwendungsfall könnte es also schneller sein, statt des DirectBufferedImages ein normales BufferedImage (TYPE_INT_*) zu nehmen, und den int[]-Array, der die Daten enthält, bei Bedarf direkt nach OpenGL rüberzuschaufeln. So ein Kopieren eines Blockes kann schneller sein, als wenn man alle intern-versteckten Optimierungen durch einen eigenen Bildtyp aushebelt.



Das ist interessant. Werd ich mal im Hinterkopf behalten und demnächst austesten.


----------



## Marco13 (18. Mrz 2011)

muckelzwerg hat gesagt.:


> Du verwendest zum Zeichnen doch das SunGraphics2D Objekt? Und das schiebt den ganzen Schmodder in die RenderQueue.


So einfach ist das IMHO nicht...


> Ich denke, es geht nur darum, dass man den Inhalt des BufferedImages nicht mehr in die OpenGL-Textur kopieren muss?



Ursprünglich ja: Wenn man über ein Graphics in ein BufferedImage malt, dann landen die Daten i.a. früher oder später in einem int[]-Array. Diesen Array kann man dann manuell nach GL kopieren, und gut ist. 

Der Gedanke beim DirectBufferedImage war jetzt, sich dieses Umkopieren zu sparen, und dafür zu sorgen, dass das, was man mit dem Graphics2D malt, _direkt_ im GL-Speicher landet. Das funtkioniert auch. Das Problem trat aber auf, wenn man über dieses Graphics2D ein BufferedImage in ein DirectBufferedImage reinmalen wollte:
- Wenn man ein BufferedImage in ein anderes BufferedImage reinmalen will, dann läuft das (ganz, ganz stark vereinfacht, und unter Abstraktion der angesprochenen "Magie") darauf hinaus, dass er erkennt: "Ah, hier ein int[]-Array, da auch ein int[]-Array, das kopier' ich einfach rüber". (Das lag dann irgendwo in den Klassen java2d.Blit, java2d.loops & Co). 
- Wenn man aber ein BufferedImage in ein _Direct_BufferedImage reinmalen will, dann funktionieren diese Optimierungen nicht - irgendwo in der Nähe der "Blit"-Klasse sagt er dann: "Hier ein int[]-Array, und da ein ... WTF? :autsch: Das kenn' ich nicht, aber ein int[]-Array ist es nicht..." und dann überträgt er praktisch jeden einzelnen Pixel vom Quellbild ins Zielbild. Das landet zwar dann ohne weiteres Umkopieren direkt im GL-Speicher, aber weil alle Pixel einzeln gesetzt werden, ist es gähnend langsam...

Wie gesagt, das ist eigentlich ein Spezialfall, wo eben ein BufferedImage reingemalt werden soll - bei Text und Shape2Ds macht es vielleicht keinen Unterschied... werd' ich bei Gelegenheit mal testen...


----------



## muckelzwerg (18. Mrz 2011)

In der Blit(...) war ich auch gerade. Wo findet denn der Test statt, was für ein Datenobjekt kopiert werden soll? Das müsste doch in SunGraphics2D sein?
Ich muss ja mal gestehen, dass ich durch Blit() und MaskedBlit() nicht so hundertprozentig durchsteige. ^^

Wie ist es denn andersrum, kann man denn nicht das Int[] aus dem BufferedImage direkt in Jogl als Textur oder VBO verwenden?


Edit: Habs gefunden. "RenderImageCopy" in "DrawImage.java" meinst Du?

Edit2: Sorry "VBO" ist natürlich quark. Ich meinte FBO.


----------



## Marco13 (18. Mrz 2011)

Ich weiß die Stelle nicht mehr genau. Ich hatte beim Zeichnen in das DirectBufferedImage dann in der Methode "public void setDataElements(int x, int y, Object obj)" einen Break gesetzt und mal geschaut, wie er da hin kommt, und das ist ein langer, steiniger Weg vom "drawImage"-Aufruf bis zu dieser Methode - irgendwo dazwischendrin liegen die beiden Bilder (Direct und nicht-Direct) wohl als "SurfaceData"-Objekte mit verschiedenen(!?) "SurfaceTypes" vor, und irgendeine "Converter-Registry" (oder so) kannte die Konvertierung nicht, und deswegen wurde jedes Pixel mit der o.g. Methode einzeln gesetzt. Ich müßte nochmal länger und systematischer schauen, ob man da noch was drehen könnte, aber erstens hat man auf die sun-Klassen ja nicht viel Einfluß, und zweitens habe ich nicht sooo die Zeit dafür - einen int[]-Array nach GL zu kopieren sollte so schnell gehen, dass die Zeitliche Meßlatte für sämtliche Workarounds und Tweaks schon ziemlich hoch liegen dürfte...

Den Array direkt zu verwenden geht nicht ohne weiteres. Die Daten liegen einmal im RAM und einmal auf der Grafikkarte. Man kann zwar theoretisch, manchmal, vielleicht, und unter ganz bestimmten Bedinungen, irgendwie, den Speicher von der einen auf die andere Seite "Mappen", aber AFAIK nicht "dauerhaft". Im Moment sehe ich jedenfalls keine praktikable(!) Möglichkeit, sich das Rüberkopieren zu ersparen.

Sicher, für eine Echtzeitübertragung von einem "Strom" von BufferedImages (z.B. aus einer Webcam) wäre das schon praktisch, aber dafür müßte ich mir erstmal die sun-Klassen ziehen, damit man da in Eclipse schneller drin rum-navigieren kann (Referenz- und Definitionssuche...) - bisher hatte ich es nur in so einem Online-Code-Anseh-Teil nachgeschaut...


----------

