# VolatileImage langsam



## Kr0e (18. Jul 2010)

Hallo,

Ich suche die Möglichkeit, Swing GUI Elemente in ein Bild zu zeichnen. Quasi einer Art Screenshot.
Als ich einfach ein BufferedImage benutzt habe, ist mir aufgefallen, dass das recht lang dauern kann bei großen
Fenstern. (Z.B. 1680x1050) Für einen Screenshot ist es natürlich egal ob es 5 ms oder 250 ms dauert.

Aber ich wollte das schon ein paar mal öfter pro Sekunde machen... Etwa 30 mal.
Also hab ich ein VolatileImage genommen zum rendern. DAs zeichnen ging sehr schnell (etwa 3 - 5 ms).

Allerdings bringen mir ja anscih die Daten im VolatileImage erstmal nichts. Ich such eine Möglichkeit,
diese Daten nun iwie effizient auslesen zu können oder bzw. iwie an den internen Datenpuffer
heranzukommen.

Gibt es da Ideen/Vorschläge/Lösungsansätze ?

Ich könnte natürlich das VolatileImage einfach eiskalt wieder in ein BufferedImage zeichnen, aber das ist
ja relativ sinnfrei.

Danke schonmal!

Gruß,

Chris


----------



## Marco13 (18. Jul 2010)

Falls das so eine Art "Remote Desktop Dingens" werden soll: Man kann vesuchen, nur die Bereiche zu zeichnen, die sich auch geändert haben, ggf. mit einem eigenen RepaintManager. Wenn sich 30 mal in der Sekunde das gesamte Bild ändert, ist man dann natürlich screwed. Ich habe da nur die Erfahrung gemacht, dass es stark von der Art des BufferedImages abhängen kann, wie schnell das ganze ist (TYPE_INT_RGB war z.B. recht schnell, alles mit TYPE_BYTE... ziemlich lahm).


----------



## Kr0e (18. Jul 2010)

Ahh perfekt Marco13! Genau dich wollte ich hier genaugenommen auch erwischen.
Es geht eigentlich mal wieder um das SwingOpenglTexture etc. Problem.

Du hast ja Swogl geschrieben und ich fand die Idee Swing auf Texturen zu zeichnen einfach genial.
Leider störte es mich, dass Swogl teilweise nicht ganz soo flott war.

Du benutzt zwar einen Repaintmanager, aber ich glaube das Problem ist, dass das Zeichnen nciht hardwarebeschleunigt ist.

Ich habe auch eine Idee, wie Swogl vlt sehr viel schneller werden könnte (Falls du daran nocht arbeitest...):

Swogl rendert ja quasi Swing in ein BufferedImage und dann die Daten aus dem Image in eine OpenGL Texture.
Du arbeitest ja mit dem TextureRenderer von JOGL, also wird intern iwas mit Gl.glTexSubImage2D benutzt.

Vor einiger Zeit habe ich einen JOGL-VideoRenderer geschrieben, der GStreamer-Java nutzt. Bei HD Movies hatte ich das Problem,
dass das Hochladen von 1920x1080 Frames extremst lang gedauert (Außerdem 70% Cpu!) hat. Und ich habe mich gefragt, wie das z.b. der Flashplayer oder der VLC Player macht. 

Die Lösung war es, ein PixelBufferObject (PBO) zu benutzen. Damit war die Zeit fast auf 3 ms gesunken.
Die PBOs benutzen die Hardwarebeschleunigung von der GRafikkarte, um DAten in den Speicher zu laden.

Bei Swogl könnte man dann wenigstens das Kopieren des BufferedImage auf die Grafikkarte sehr stark beschleunigen.
Aber in meinem Fall dauert es schon alleine 250 ms ein JFrame ganz simpel mit Jframe.paint(); in ein BufferedImage zu zeichnen,
ohne Swogl jetzt und die ganze OpenGL-Geschichte. Ich vermute, dass liegt daran, das extreme Datenmengen von dem nativen Fenster aus in den java-internen Heapspace geladen werden müssen. Das VolatileImage war da unglaublich schnell.

Aber ich suche nun iwie eine Möglichkeit diese Daten des VolatileImage effizient auch nutzen zu können!
Davon könnte dann sicher auch Swogl profitieren...

Gruß,

Chris


----------



## Marco13 (18. Jul 2010)

> Ahh perfekt Marco13! Genau dich wollte ich hier genaugenommen auch erwischen.



Eine PN wäre eine Alternative  (aber irgendwie habe ich so dumpf in Hinterkopf, dass ich zwar oft auf deine Threads antworte, aber nie wirklich DEN hilfreichen Hinweis geben konnte  ???:L ).



> Ich habe auch eine Idee, wie Swogl vlt sehr viel schneller werden könnte (Falls du daran nocht arbeitest...):



Ich habe schon länger nicht mehr daran gearbeitet, aber eher ... "unfreiwillig". Also, ich würde da gerne mal wieder RICHTIG weitermachen, aber ... ja, frecherweise werde ich genötigt, mir jeden Tag 8 Stunden im Büro den A. plattzusitzen  (Wobei die nicht für Swogl aufgewendete Freizeit primär in Java+GPGPU geflossen ist). Einer der ersten größeren Schritte wäre unter anderem, zu versuchen, Swogl etwas OpenGL-binding-agnostischer zu machen. Also nicht mehr unbedingt den TextureRenderer zu verwenden, und eine klarere Trennung zwischen der Event- und Component-Logik, und dem eigentlichen Rendering mit "irgendeiner" OpenGL-Anbindung.



> Vor einiger Zeit habe ich einen JOGL-VideoRenderer geschrieben, der GStreamer-Java nutzt. Bei HD Movies hatte ich das Problem, dass das Hochladen von 1920x1080 Frames extremst lang gedauert (Außerdem 70% Cpu!) hat. Und ich habe mich gefragt, wie das z.b. der Flashplayer oder der VLC Player macht.
> 
> Die Lösung war es, ein PixelBufferObject (PBO) zu benutzen. Damit war die Zeit fast auf 3 ms gesunken. Die PBOs benutzen die Hardwarebeschleunigung von der GRafikkarte, um DAten in den Speicher zu laden.


GStreamer kannte ich jetzt noch nicht - die schicken die Daten direkt in ein PBO, das dann mit JOGL oder so gerendert wird? Grundsätzlich ist das ja rattig schnell. Wenn man aber (wie bei Swogl) das ganze in eine Lightweight-Component rendern will, muss dafür ein eigener GL-Context erstellt und wieder etliches umkopiert werden, wodurch es wieder schrecklich langsam wird  (Über die näheren Gründe wurde hier auch schon in anderen Threads geredet, da kann Guest2 aka Fancy mehr dazu sagen - DA gibt's aber das Problem, dass man NICHT mit einer PN an ihn rankommt  )



> Bei Swogl könnte man dann wenigstens das Kopieren des BufferedImage auf die Grafikkarte sehr stark beschleunigen.
> Aber in meinem Fall dauert es schon alleine 250 ms ein JFrame ganz simpel mit Jframe.paint(); in ein BufferedImage zu zeichnen,
> ohne Swogl jetzt und die ganze OpenGL-Geschichte. Ich vermute, dass liegt daran, das extreme Datenmengen von dem nativen Fenster aus in den java-internen Heapspace geladen werden müssen. Das VolatileImage war da unglaublich schnell.
> 
> Aber ich suche nun iwie eine Möglichkeit diese Daten des VolatileImage effizient auch nutzen zu können!



Also hast du - ganz grob zusammengefasst - vor, die Daten nicht in ein BufferedImage zu rendern, sondern in ein VolatileImage, davon ausgehend, dass dieses die Daten schon im Grafikspeicher vorliegen hat, und man sie dann im Idealfall schon 1:1 direkt (und ohne weiteres Kopieren) _als Textur verwenden_ kann? 
Man müßte vielleicht mal den Quellcode von VolatileImage durchforsten, ob dort irgendwo ein verräterisches

```
private long pointerToVRAM;
```
oder so drinsteht :reflect: :hihi:


----------



## Kr0e (19. Jul 2010)

Hi,

ja genau sowas meinte ich! Zu GStreamer:

Nein, die machen das mit PBO nicht von Haus aus. Das habe ich gemacht, um es lauffähig zu machen unter Java.
Der VLC/WMP benutzen ähnlcihe Techniken allerdings mit DirectX.

Ich hatte nämlich dann den Gedanken das Umkopieren durch einen PBO zu beschleunigen.
Ich bin grad auch auf der Arbeit und mache eine ähnliche Tätigkeit wie du 

Ich werde später mal nach diesem eventuellen Pointer suchen, denn wenn die Grafikkarte mit im Spiel ist,
dann bin ich mir verdammt sicher, dass das im Prinzip ne Textur sein düfte, wobei das mehr als ein Hack
bezeichnet werden müsste.

Ich finde es sowieso ziemlich umständlich, dass SUN damals die Java2D schnittstelle nicht etwas globaler
verfasst hat. Das man "mal eben" eine eigene RenderPipeline nehmen kann oder ähnliches...

Ok, native AWT GUI-Elemente in eine Textur zu zeichnen ist schon etwas unsauber, aber grad Swing ist ja sowieso pur Java,
von daher hätte man da vlt. mal in die Richtung Java3D etc. denken sollen.

Aber nun gut. Ich habe gstern gesehen, dass es auch alternative Java GUIs gibt.
Eine ziemlich interessante ist Apache Pivot. Die ist wohl in der Lage, direkt ohne
Frame oder JFrame mit einem Graphics2D Objekt sich selbst zu zeichnen.

Wenn ich nichts bzg. Texturdaten aus dem VolatileImage finde, werde ich vermutlcih in diese Richtung gehen.

Gruß,

Chris


----------



## Marco13 (19. Jul 2010)

Ja, hab mal geschaut: VolatileImage ist natürlich erstmal abstract, und die Implementierung ist geheim  Insgesamt gibt's im Kontext von BufferedImages und VolatileImages einiges, was sich dem direkten Zugriff entzieht. Dort wird es dann stark plattformspezifisch, ob und wie hardwarebeschleunigte Bilder verwendet werden (die wohl allgemein "Managed Images" heißen). Es gibt zwar ein paar (wenige) Infos, z.B. auf VolatileImage Q&A | Java.net oder das was oben in den Release Notes von New Features in Java 2D(TM) Technology steht, aber ... die Innereien sind dann nicht so zugänglich. Der "globalere" Ansatz, den du angesprochen hast, dürfte nicht zuletzt an der Anforderung gescheitert sein, dass Swing auf einer GeForce 2 unter Windows genauso laufen sollte wie auf einer Radeon HD 5970 unter Linux... Und ich vermute, du weißt das Swing eben nicht "pur Java" ist, sondern schon OpenGL- und DirectX-Beschleunigung verwenden kann....

Apache Pivot hatte ich seltsamerweise noch nie gehört, aber irgendwie ist mir auch nicht ganz klar, was das sein soll - außer einer ... sehr.... direkten (also "parallelen") Alternative zu Swing ???:L


----------



## Kr0e (19. Jul 2010)

Apache Pivot ist eine komplette GUI Alternative, nur dass es, anderes als bei Swing, sehr einfach ohne natives Fenster lauffähig ist. Also praktisch komplett virtuell mit Hilfe eines Graphics2D Object. Natürlcih treten dann wieder die selben Geschwindigkeitsprobleme auf, wie bei Swing und BufferedImages. Aber bei Swing musste man ja immer so rumfrickeln, damit es überhaupt ohne natives Fenster sich in einen Puffer zeichnen lässt...


Nochmal zurück zum VolatileImage:

Wenn man nicht an die Daten des VolatileImages herankommen kann, macht das VolatileImage doch eigentlich null Sinn, oder ?
Ich meine ist ja gut und schön dass man in ein VI ganz fix zeichnen kann, aber um dieses Image dann auf dem Bildschirm auszugeben, muss man es ja dann wieder mit Hilfe von Graphics.drawImage iwo draufzeichnen. Bei mir dauert das Zeichnen von einem gefüllten VI auf ein BufferedImage genauso lang, wie das direkte Zeichnen in ein BufferedImage. Ich habe gesehen, dass es wohl einen Unterschied gibt bei drawImage. Wenn die Größenverhältnisse stimmen, wird intern einer Art copyImage benutzt...

Aber aufgrund von sehr hohen Auflösungen streikt die CPU und verbraucht 1. sehr viel Rechenleistung und 2. benötigt dafür >200ms.

Oder vlt. einer Art BufferedImage das einen direct ByteBuffer als Speicherbereich nutzt oder so, damit das Umkopieren schneller geht. Ich meine sooo speziell ist der Anwendungsfall doch nicht, da muss es doch iwas von Java geben, um Images fix umzukopieren. Denn das rendern von Swing in ein VI geht soo unglaublich schnell... 4-5 ms!! 

Gruß,

Chris


----------



## Marco13 (19. Jul 2010)

Kr0e hat gesagt.:


> Apache Pivot ist eine komplette GUI Alternative, nur dass es, anderes als bei Swing, sehr einfach ohne natives Fenster lauffähig ist. ... Aber bei Swing musste man ja immer so rumfrickeln, damit es überhaupt ohne natives Fenster sich in einen Puffer zeichnen lässt...



Ja, das ist etwas hakelig. Und falls du das mit dem "globaleren Ansatz" meintest, stimme ich da natürlich zu. 

Die Frage, wann ein VolatileImage Sinn macht, wird ja in dem verlinkten Blog-Eintrag beantwortet (Kurz: "Selten"  ). Das Problem ist wohl nicht zuletzt, dass bestimmte Aspekte der Erhaltung des Speichers usw. außerhalb es Einflußbereichs der JVM liegen...



> Oder vlt. einer Art BufferedImage das einen direct ByteBuffer als Speicherbereich nutzt oder so, damit das Umkopieren schneller geht.



Ja, sowas hatte ich ja "damals" in diesem Beitrag schon angedeutet. Ausprobiert hatte ich es bisher noch nicht, aber auch nicht vergessen - das liegt irgendwo in einer langen, langen Queue (und ist durch diese Thread (wieder?) ein bißchen nach vorne gerutscht).


----------



## Guest2 (21. Jul 2010)

Moin,

wie das VolatileImage intern verdrahtet ist, habe ich mir auch noch nie genau angesehen. Und kann damit eigentlich auch nicht direkt weiterhelfen. 

Aber, wenn Swing die OpenGL Beschleunigung nutzt (was imho default immer noch nicht so ist), dann hat z.B. das JPanel intern eine gültige TextureID. Greift man diese von extern ab und zeichnet in die dazugehörige Textur etwas rein, ist dies auf dem JPanel sichtbar. Andersrum würde ich vermuten, dass wenn man die Textur ausliest, man auch das aktuelle "Aussehen" des JPanel zurückbekommt. Ich würde aber auch vermuten, das wenn das JPanel nicht sichtbar ist, auch die Textur nicht gezeichnet wird, was evtl. zu weiteren Fummeleien führen könnte.

Auch allgemein ist der Zugriff auf die Textur nicht einfach. Während das "rausfummeln" der TextureID fast noch trivial ist, wird der richtige Zugriff auf die Textur richtig "haarig". Zum einem muss der eigene OpenGL Kontext "richtig" mit dem OpenGL Kontext von Swing verknüpft werden und zum anderen müssen eigene OpenGL Befehle teilweise in den OpenGL Thread und Kontext von Swing injiziert werden. Dabei ist das alles natürlich nicht dokumentiert und wenn irgendwo auch nur eine Kleinigkeit nicht stimmt geht gar nichts. Wenn es schlecht läuft, macht es auch Beep und der Rechner startet neu.

Und man muss sich dabei bewusst sein, dass jedes kleine VM Update einem den Fuß abschneiden kann.

Wenn sich einer da reinarbeiten will, empfehle ich die GLJPanel von JOGL mal genauer zu untersuchen. Darin gibt es eine innere Klasse die den Einstiegspunkt für den Zugriff auf die Textur von JPanel darstellt. Aber erstens ist der Quelltext da nicht "schön" *hust* und zweitens nicht lauffähig. Um eigene "Forschung" und hüfthohes waten durch die Swing und JOGL Innereien kommt man da kaum rum.

Aber, als ich mir das letzte mal das angesehen habe, war das noch zu Java u19 evtl. hat sich inzwischen bei u21 was grundlegend verbessert?


@Marco: Ja, bin bei mir an der Oberfläche. GLWindow und GLPanel sind kein Thema, aber das GLJPanel habe ich mir bisher noch nicht wirklich angetan . Den Thread hier hab ich sogar vorher auch schon mitgelesen, aber da ich keine wirkliche Antwort oder Tipp geben kann (wer in die oben erwähnten "Forschungen" einsteigt, wird merken warum ), kam auch bisher noch nix von mir. 

Gruß,
Fancy


----------



## Kr0e (21. Jul 2010)

Hallo Fancy,

ich denke wir stoßen mit so einem Vorhaben an die Grenzen das machbaren. Eigentlich schade, ich könnte mir vorstellen, dass es vom Grundgerüst her nicht viel mehr Aufwand gewesen wäre, da evt. manuelle RenderTargets zu unterstützen. Und das hätte Java einen echten Boost gegeben. Ich meine, Java hat schon eine gigantische Standardbibliohtek, käme jetzt noch eine 3D GUI für OpenGL hinzu, die über Netbeans Matisse GUI Builder erstellt werden kann.. Oje.. Da hätten es andere Sprachen sehr schwer 

Alles in allem seh ich langsam ein, dass es da noch keine Lösung gibt. (Das Argument, dass ein neues Update vieles verwerfen kann von Oracle/Sun^^) Da ich unbedingt eine GUI brauche und alle Ansätze, die es für Java gibt sich noch in Alpha/Beta-Stadien befinde und z. T. auch nicht weiterentwickelt werden, werde ich mich nun an eine eigene pur OpenGL-Basierende GUI setzen. Da könnte ich dann direkt auch die nativen Video(GStreamer)-OpenGL Texturen benutzen, ohne die wieder auf ein BufferedImage zu kritzeln.

Aber ich danke euch für diese Diskussion 

Einen schönen Abend noch!

Gruß,

Chris


----------



## Marco13 (21. Jul 2010)

Je nachdem, was da am Ende rauskommen soll: Die Texturen an sich müssen ja nicht den Umweg über's BufferedImage gehen. Nur wenn man dann zusätzlich AUF den Texturen noch Swing-Components anzeigen will. Aber vielleicht meinen wir gerade unterschiedliche Teilaspekte.


----------

