# Problem mit dem Backbuffer (VolatileImage)



## Leycarno (28. Sep 2007)

Hallo zusammen!

Ich hätte da eine Frage, die mir langsam die Nerven aufreibt (wie so oft).

Ich habe ein Frame in den Fullscreen-Modus gebracht und einige Volatile-Images in einem Threads auf einen Backbuffer (ebenfalls Volatile) gedrawt. Das passiert nun alle 20 Millisekunden und die CPU wird so gut wie nicht beansprucht. Selbst der zweite Thread, der zur Berechnung zuständig ist (alle 10 Millisekunden) beansprucht die CPU noch überhaupt nicht...

Nun muss das ganze natürlich noch auf den Bildschirm, also wird das Graphic-Object per dispose gesperrt und:

frame.getGraphics.drawImage(backbuffer, null, null);

aufgerufen. Es läuft auch nicht schlecht. Der "nanoTime"er macht die Darstellung recht flüssig (1024*768) aber so RICHTIG flüssig, wie ich es mit C++ und DirectX gewohnt war ist es nicht.  
Offensichtlicher Grund: Das Malen auf den Bildschirm - und nur das! - führt dazu, das die CPU von 1-2% Beanspruchung auch 70% und mehr steigt -> Also wird es NICHT von der Grafikkarte erledigt...


Nun kann ich mir nur vorstellen, dass der oben genannte Aufruf nicht mehr mit der Grafikkarte arbeitet oder das der Frame (AWT) nebenbei noch einen Backbuffer hat, der nicht gebraucht wird.

Ich habe es vorher übrigens mit createBufferStrategy (Also AWT-DoubleBufferung ) probiert, was im Grunde das gleiche Ergebnis brachte...



Also die Frage an Euch: Hat jemand eine Idee wie schaffe ich es, den Backbuffer auf den Bildschirm zu schicken, ohne das die CPU anfängt so stark zu rotieren?


Wenn ich Code schicken soll kann ich das nachholen - aber ich frage erst einmal so, weil ich stark vermute, das es (wie so oft) eine recht einfache Lösung gibt... Vielleicht ja auch irgendwas, was Java 1.6 nun hat... oder Vielleicht sollte ich irgendeine andere Lib benutzen...

Vielen Dank für Antworten

Gruß, Ley


----------



## Quaxli (28. Sep 2007)

Hi,

bißchen Code außenrum wäre nicht schlecht. So läßt sich nur raten was es sein könnte. Ein Anmerkung habe ich noch:


```
frame.getGraphics()...
```

Das tut man nicht, wenn es sich nicht vermeiden läßt, sondern überschreibt die paint-Methode oder paintComponent-Methode des jeweiligen Objektes.


----------



## Leycarno (28. Sep 2007)

Ich dachte es würde reichen, folgendes zu deklarieren:

```
this.frame.setIgnoreRepaint(true);
```
Wenn ich die paint-Methode überschreibe -> Welches Graphics soll ich da übergeben?


Ok, dann zunächst einmal der Thread, der für die Darstellung zuständig ist:


```
public void run()
        {
            Thread.currentThread().setPriority(10);
            while (engineIsRunning)
            {
                if (backBuffer == null)
                {
                    createBackBuffer();
                }
                do
                {
                    // Backbuffer testen
                    GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
                    GraphicsConfiguration graphicsConfiguration = graphicsEnvironment.getDefaultScreenDevice().getDefaultConfiguration();
                    int valCode = backBuffer.validate(graphicsConfiguration);
                    if (valCode == VolatileImage.IMAGE_INCOMPATIBLE)
                    {
                        createBackBuffer();
                        // Erstellt das Volatile-Image -> Vielleicht wichtig zu wissen: 
                        // Graphics2D g = (Graphics2D) this.backBuffer.getGraphics();
                        // g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                    }
                    // Backbuffer clearen
                    backBuffer.getGraphics().fillRect(0, 0, displayMode.getWidth(), displayMode.getHeight());
                    // Rendern
                    if (aktLevel != null)
                    {
                        if (levelList.containsKey(aktLevel))
                        {
                            if (levelList.get(aktLevel).isRunning())
                            {
                                levelList.get(aktLevel).drawLevel();
                            }
                        }
                    }
                    backBuffer.getGraphics().dispose();
                    // Kopieren des back buffers auf den Bildschirm
                    // benutzt wird -> this.graphics2D = (Graphics2D) this.frame.getGraphics();
                    graphics2D.drawImage(backBuffer, null, null);
                } while (backBuffer.contentsLost());

                try
                {
                    TimeUnit.MILLISECONDS.sleep(20);
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
```

Der Code ist aus der abstracten Engine-Klasse, die einen Frame-Member hat (kein extends).
Die ruft die abstracte Methode des aktuellen Levels auf (levelList.get(aktLevel).drawLevel(); ) 
die wiederum die abstracten drawSprite()-Methoden der jeweiligen Sprites aufruft, die auf den Backbuffer malen.

Hier die Draw-Methode - Sie wird in der jeweiligen Realisiation der abstracten Methode "drawSprite" aufgerufen,
damit die Reihenfolge der zu malenden Sprites vom späteren Programierer festgelegt werden kann:


```
public void draw()
    {
        // Nur malen, wenn das Image erstellt und nicht bis zum "Nichts" runterskaliert wurde...
        if (this.volatileImage != null && this.scaleX != 0.0 && this.scaleY != 0.0)
        {
            AffineTransform transform = new AffineTransform();

            transform.shear(this.shearX, this.shearY);
            transform.rotate(Math.toRadians(this.degree), this.positionX, this.positionY);
            transform.translate(this.positionX, this.positionY);
            transform.scale(this.scaleX, this.scaleY);

            this.backBuffergraphics.drawImage(this.volatileImage, transform, null);
        }
    }
```

Ich könnte noch mehr posten, aber ich will nicht alles mit Code vollspamen.
Wenn mehr nötig ist - poste ich es natürlich 

Gruß Ley


----------

