[java] volatileImage en hoe flickering vermijden...

Pagina: 1
Acties:

Verwijderd

Topicstarter
Beste,

Wat wil ik doen?
ik wil een rechthoek teken op een JPanel en die van links naar rechts laten botsen.

Wat is het probleem?
gewoon, bufferedImage, volatileImage telkens heb ik flickering (oftewel het bovenste stuk van mijn shape, hier rechthoek) staat al x pixels verder dan onderste stuk (omdat het onderste niet op tijd gerefreshed is?).

Wat is mijn vraag?
Ik ben al een week aan het proberen, heb nu eindelijk na veel info te lezen een werkend voorbeeld met volatileImage. Ziet er iemand of er dingen sneller kunnen, of er grote fouten in zitten die het tekenen vertragen? hints? }:O

Dit is mijn code: (er is natuurlijk ook een klasse die een JFrame aanmaakt en de JPanel er aan toevoegt)
Java: VmainPaneel.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.VolatileImage;
import javax.swing.*;

public class VmainPaneel extends JPanel implements ActionListener {
    // image creation
    final int w = 400;
    final int h = 400;
    int richtingSnelheid = 10;
    int drawImagePosX = 0;
    VolatileImage vImg = createVolatileImage(w, h);

    public VmainPaneel(){
        renderOffscreen();
        // start een timer die 10x/s een actionEvent triggert
        javax.swing.Timer tijdje = new javax.swing.Timer(1000/10, this);
        tijdje.start();
    }

    public VolatileImage createVolatileImage(int width, int height) {   
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
        VolatileImage image = null;

        image = gc.createCompatibleVolatileImage(width, height);

        if (image.validate(gc) == VolatileImage.IMAGE_INCOMPATIBLE) {
            image = this.createVolatileImage(width, height);
            return image;
        }
        return image;
    }

    void renderOffscreen() {
        do {
    
            if (vImg.validate(getGraphicsConfiguration()) ==
                VolatileImage.IMAGE_INCOMPATIBLE){
                // old vImg doesn't work with new GraphicsConfig; re-create it
                vImg = createVolatileImage(w, h);
            }

            Graphics2D g = vImg.createGraphics();

            // miscellaneous rendering commands...      
            g.setColor(Color.red);
            Rectangle2D.Double rechtje = new Rectangle2D.Double(20, 20, 250, 550);  
            g.fill(rechtje);            

            g.dispose();
        } while (vImg.contentsLost());
    }

    public void paintComponent(Graphics gScreen)
    {
        System.out.println("paintComponent gestart");
        super.paintComponent(gScreen);
        do {
            int returnCode = vImg.validate(getGraphicsConfiguration());
            if (returnCode == VolatileImage.IMAGE_RESTORED) {
                // Contents need to be restored
                renderOffscreen();      // restore contents
            } else if (returnCode == VolatileImage.IMAGE_INCOMPATIBLE) {
                // old vImg doesn't work with new GraphicsConfig; re-create it
                vImg = createVolatileImage(w, h);
                renderOffscreen();
            }
            gScreen.drawImage(vImg, drawImagePosX, 0, this);
        } while (vImg.contentsLost());
        System.out.println("paintComponent voltooid");
    }

    public void actionPerformed(ActionEvent e) { 
        /* telkens als de timer dit event triggert, wordt er een repaint opgeroepen. */

                System.out.println("timer tik"); //debug
        
      // verander de richting als de "blok" de rand raakt
        if((drawImagePosX >= getWidth() - w)
                ||  (drawImagePosX < 0))
        { 
            richtingSnelheid *= -1;
        }
        // verander de horizontale positie adhv richting en snelheid en repaint
        drawImagePosX += richtingSnelheid;
        repaint();
    }
}


Of weet er iemand een andere manier om in Java van die flickering af te geraken?

thanx!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 22:28

Matis

Rubber Rocket

Ikzelf heb niet zo veel ervaring met Java, in .Net kun je je applicatie syncen op je refreshrate van je scherm.

Of iig laten redrawen ;)

[ Voor 11% gewijzigd door Matis op 17-12-2009 21:26 ]

If money talks then I'm a mime
If time is money then I'm out of time


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 00:49
Lijkt me dat je double buffering wil gebruiken om flikkeren te voorkomen.

Zie bijvoorbeeld hier: Double Buffering and Page Flipping

  • zezke
  • Registratie: September 2006
  • Laatst online: 20:00
Inderdaad double buffering en page flipping zou je probleem moeten oplossen.

Verwijderd

Topicstarter
Soultaker schreef op donderdag 17 december 2009 @ 21:28:
Lijkt me dat je double buffering wil gebruiken om flikkeren te voorkomen.

Zie bijvoorbeeld hier: Double Buffering and Page Flipping
Double Buffering and Page Flipping zijn enkel te gebruiken in full-screen exclusive mode.
Op zich zou dat kunnen een oplossing zijn voor een game of zo, maar ik zou liever in mijn venstertje/JFrame blijven.
Ik ga er vanuit dat een degelijke programmeertaal als JAVA toch moet in staat zijn om in een swing venster deftig te renderen? of niet?

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 22:41

Creepy

Tactical Espionage Splatterer

Double buffering alleen in fullscreen exclusive mode? Dat is onzin. Ik stel voor dat je even zoekt op "double buffering java graphics" en die informatie even bekijkt ;) Voor page flipping geldt dat wel ja

[ Voor 9% gewijzigd door Creepy op 17-12-2009 22:20 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Verwijderd

Topicstarter
Creepy schreef op donderdag 17 december 2009 @ 22:19:
Double buffering alleen in fullscreen exclusive mode? Dat is onzin. Ik stel voor dat je even zoekt op "double buffering java graphics" en die informatie even bekijkt ;) Voor page flipping geldt dat wel ja
super, ik ga eens zoeken en testen, i'll let you know.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
(Na vele uren zoeken ... :) )
Mijn probleem is niet flickering, maar tearing!
Creepy schreef op donderdag 17 december 2009 @ 22:19:
Double buffering alleen in fullscreen exclusive mode? Dat is onzin. Ik stel voor dat je even zoekt op "double buffering java graphics" en die informatie even bekijkt ;) Voor page flipping geldt dat wel ja
Zou vaak wel mogelijk zijn om page flipping te doen zonder fullscreen exclusive mode: volgens deze topic (ander forum) kan je dit testen.

Java voorziet bij de klasse BufferCapabilities een paar methods hiervoor:
  • isFullScreenRequired: whether page flipping is only available in full-screen mode. If this is true, full-screen exclusive mode is required for page-flipping.
  • isPageFlipping:whether or not the buffer strategy uses page flipping; a set of buffers that uses page flipping can swap the contents internally between the front buffer and one or more back buffers by switching the video pointer (or by copying memory internally). A non-flipping set of buffers uses blitting to copy the contents from one buffer to another; when this is the case, getFlipContents returns null
  • isMultiBufferAvailable: whether or not page flipping can be performed using more than two buffers (one or more intermediate buffers as well as the front and back buffer).
Mijn test:
Java:
1
2
3
4
5
6
7
8
9
Canvas gui = new Canvas();
...
gui.createBufferStrategy(2);
BufferStrategy strategy = gui.getBufferStrategy();
BufferCapabilities cap = strategy.getCapabilities();
// schrijf = System.out.println         
schrijf("isPageFlipping?"+cap.isPageFlipping());
schrijf("FullScreenRequired? "+ cap.isFullScreenRequired());
schrijf("isMultiBufferAvailable?" + cap.isMultiBufferAvailable());


geeft als output:
FullScreenRequired? false
isMultiBufferAvailable?false
isPageFlipping?true

Dus:
pageFlipping is mogelijk
FullScreen mode is niet nodig voor pageflipping
met meer dan twee buffers werkt pageflipping niet (maar ik heb maar 2 buffers, dus geen prob)

Maar mijn probleem blijft (tearing: een deel van blokje is al ververst terwijl ander nog niet, waardoor je soort van verschuiving ziet).
Ook al geprobeerd om mijn code te draaien met "-Dsun.java2d.opengl=True", no change.
Ik denk dat ik een manier moet vinden om een soort van vsync te doen. Maar hoe is een raadsel! Ik begin eraan te twijfelen of java dit kan.

Als jullie willen post ik volledige code, kunnen jullie zelf eens testen,
(mijn specs: Acer Travelmate 5730G, Win Vista Business, 4GB ram, grafische kaart heeft 1500 mb shared ram.)

thanks!

Acties:
  • 0 Henk 'm!

  • boe2
  • Registratie: November 2002
  • Niet online

boe2

'-')/

Het lijkt nochtans een zuiver doublebuffering probleem. Het is de eerste keer dat ik over een VolatileImage hoor (ik werk dan ook niet met java), maar als ik erover lees kan je dan niet je problemen oplossen door een "gewone" image te gebruiken?

'Multiple exclamation marks,' he went on, shaking his head, 'are a sure sign of a diseased mind.' - Pratchett.


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 16-09 09:15

Janoz

Moderator Devschuur®

!litemod

Boeboe schreef op zondag 20 december 2009 @ 14:09:
Het lijkt nochtans een zuiver doublebuffering probleem.
Doublebuffer probleem is flikkeren

Tearing is het niet synchroon lopen van het renderen in de computer en het renderen op het scherm.

Ten eerste is in de code al te zien dat er gebruik gemaakt wordt van double buffering en ten tweede is de omschrijving precies wat tearing inhoud. Tijdens het opbouwen van het scherm is het beeld vernieuwd waardoor halverwege het scherm al het volgende frame getekend wordt.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • naam
  • Registratie: Oktober 2007
  • Laatst online: 12-09 13:07
Ik ben zelf niet bekend met java, maar ik denk dat je moet zoeken naar het synchen van de frames van je app en de frames van je beeldscherm, in games staat soms bij de beschrijving "synchinc prevents tearing" of iets in die trant :)

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Het probleem is echt wel tearing.

Dit is de code die ik nu heb, het maakt gebruik van Bufferstrategie en pageFlipping (denk ik, hoop ik, vermoed ik, ... ). Het is 1 file, dus mss kan iemand dit snel eens uittesten... _/-\o_

Verder ga ik nog eens goed de lesson lezen. Ik heb al een tegenstelling gevonden:
hier staat "One such technique that is only available in full-screen exclusive mode is a form of double-buffering called page-flipping. " Terwijl hier duidelijk staat dat je met isFullScreenRequired() kan testen "whether or not full-screen exclusive mode is required before hardware page-flipping should be attempted". mmmm in dezelfde doc zeggen ze dus dat het niet kan en verder dat je kan testen of het kan |:(

Java: MyGame.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import java.awt.BufferCapabilities;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;

public class MyGame {
    private static final int FRAME_DELAY = 1000/60; // 60fps

    
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        Canvas gui = new Canvas();
        frame.getContentPane().add(gui);
        frame.setSize(1200, 300);
        frame.setVisible(true); 
        Thread gameThread = new Thread(new GameLoop(gui));
        //gameThread.setPriority(Thread.MAX_PRIORITY);
        gameThread.start(); // start Game processing.

    }
 
    private static class GameLoop implements Runnable {
        final  int SIZE = 300;
        int richtingSnelheid = 10;
        boolean isRunning;
        int posX;
        Canvas gui;
        long cycleTime;
 
        public GameLoop(Canvas canvas) {
            gui = canvas;
            isRunning = true;
            posX = 1;
        }
        public void run() {
            cycleTime = System.currentTimeMillis();
            gui.createBufferStrategy(2);
            BufferStrategy strategy = gui.getBufferStrategy();
            BufferCapabilities cap = strategy.getCapabilities();
            
            System.out.println("FullScreenRequired? "+ cap.isFullScreenRequired());
            System.out.println("isMultiBufferAvailable?" + cap.isMultiBufferAvailable());
            System.out.println("isPageFlipping?"+cap.isPageFlipping());
            // Game Loop
            while (isRunning) {
                updateGUI(strategy);
                synchFramerate();
                updateGameState();
            }
        }
        private void updateGameState() {
            if((posX >= gui.getWidth() - SIZE)  ||  (posX <= 0))
            { 
                richtingSnelheid *= -1;
            }
            // verander de horizontale positie adhv richting en snelheid en repaint
            posX += richtingSnelheid;
        }
        private void updateGUI(BufferStrategy strategy) {
            Graphics g = strategy.getDrawGraphics();
            g.clearRect(0, 0, gui.getWidth(), gui.getHeight());
            g.setColor(Color.BLACK);
            g.fillRect(posX, 100, SIZE, SIZE); 
            g.setColor(Color.red);
            g.fillOval(posX, 100, SIZE, SIZE); 
            g.dispose();
            strategy.show();
        }
        private void synchFramerate() {
            cycleTime = cycleTime + FRAME_DELAY;
            long difference = cycleTime - System.currentTimeMillis();
            try {
                Thread.sleep(Math.max(0, difference));
            }
            catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}



Tot nu toe heb ik nooit full-screen gebruikt. Zal dat dan ook maar eens testen... = 8)7

Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 22:28

Matis

Rubber Rocket

Ik zie dat je in regel 69 een .dispose() doet op je Graphic g.

http://java.sun.com/j2se/...t/Graphics.html#dispose()

Daarmee gooi je toch je zojuist gecreëerde sprite weg, alhans, daar lijkt het mij naar. Ik heb zelf niet zoveel ervaring met het ontwikkelen van *games* in Java, maar komt daar je tearing niet vandaan?

Dat, op het moment dat hij de sprite tekent, hij meteen weer disposed wordt.

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
:) :) :) :) GEVONDEN !!!!

Heb het voorbeeld gebruikt van de java lesson. Dit voorbeeld gebruikt de FullScreenExclusiveMode :p

Samengevat: tearing vermijden in java, gebruik Full-Screen Exclusive Mode!!
Matis schreef op maandag 21 december 2009 @ 14:14:
Ik zie dat je in regel 69 een .dispose() doet op je Graphic g.

http://java.sun.com/j2se/...t/Graphics.html#dispose()

Daarmee gooi je toch je zojuist gecreëerde sprite weg, alhans, daar lijkt het mij naar. Ik heb zelf niet zoveel ervaring met het ontwikkelen van *games* in Java, maar komt daar je tearing niet vandaan?

Dat, op het moment dat hij de sprite tekent, hij meteen weer disposed wordt.
Daar heb je inderdaad een punt, maar ik had dit al gewijzigd en maakte geen verschil. De sprite werd wel gerenderd als de dispose ervoor staat... wat ik op zich raar vind.

[ Voor 5% gewijzigd door Verwijderd op 21-12-2009 14:57 ]

Pagina: 1