Results 1 to 9 of 9
  1. #1
    Macpwnage is offline Member
    Join Date
    Jul 2011
    Posts
    5
    Rep Power
    0

    Default Double Buffering

    I'm currently writing a small game (Applet) and I've ran into a problem with double buffering. Everything works just fine when I draw the game to the graphics object that is passed as a parameter to the Applet's paint method (3-5% cpu usage at 60 fps). The heavy flickering is annoying though so I've tried to implement double buffering to get rid of this.

    So I've made an image the size of the screen and then try to pass its Graphics object down to my draw methods just like I did before with the "regular" paint Graphics object and then finally draw this image to the screen. However instead of the 3-5% cpu usage it had before, it's now at a steady 25% (quadcore) and nearly completely freezes (this even happens without drawing the image to the screen).

    Trying to fix this I've figured out that the problem seems to be drawingImages to the image's graphics object as methods like drawRect() don't seem to give the same problem.
    If someone could help me with any kind of solution it would be greatly appreciated.

  2. #2
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,421
    Rep Power
    25

    Default

    Can you post a small program that compiles and executes that shows your problem.
    Wrap the code in code tags. Use the # icon above the input box.

  3. #3
    Macpwnage is offline Member
    Join Date
    Jul 2011
    Posts
    5
    Rep Power
    0

    Default

    Java Code:
    import java.applet.Applet;
    import java.awt.Graphics;
    import java.awt.Image;
    import java.io.File;
    import java.io.IOException;
    
    import javax.imageio.ImageIO;
    
    
    public class MyApplet extends Applet {
    	DrawnObject[] lotsOfObjects;
    	Image objectImage;
    	RepaintThread painter;
    	Image offScreenImage;
    	Graphics offScreenGraphics;
    	
    	public void init(){
    		
    		//load some image for our DrawnObject
    		loadImage("icon.jpg");
    		
    		//create a bunch of objects to draw
    		lotsOfObjects = new DrawnObject[4000];
    		for(int i=0; i<lotsOfObjects.length;i++){
    			lotsOfObjects[i] = new DrawnObject(i/10, i%100, objectImage);
    		}
    		
    		// create a thread repainting the applet at 60 fps
    		painter = new RepaintThread(this);
    		painter.setRunning(true);
    		painter.start();
    		
    		offScreenImage = createImage(this.getWidth(), this.getHeight());
    		offScreenGraphics = offScreenImage.getGraphics();
    	}
    	
    	public void loadImage(String s){
    		try {
    			objectImage = ImageIO.read(new File(s));
    		} catch (IOException e) {
    			System.out.println("failed to load image" + e);
    		}
    	}
    	
    	public void paint(Graphics g){
    		
    		g.clearRect(0, 0, this.getWidth(), this.getHeight());
    		// draw all objects
    		for(int i=0; i<lotsOfObjects.length;i++){
    			lotsOfObjects[i].drawObject(g);
    		}
    	}
    	
    	public void paint2(Graphics g){
    		offScreenGraphics.clearRect(0, 0, offScreenImage.getWidth(null), offScreenImage.getHeight(null));
    		for(int i=0; i<lotsOfObjects.length;i++){
    			lotsOfObjects[i].drawObject(offScreenGraphics);
    		}
    		 g.drawImage(offScreenImage, 0, 0,null);
    		
    	}
    	
    	public void update(Graphics g){
    		paint(g);
    	}
    
    }
    Java Code:
    import java.awt.Graphics;
    import java.awt.Image;
    
    
    public class DrawnObject {
    	int x,y;
    	Image image;
    	public DrawnObject(int x, int y, Image image){
    		this.x = x;
    		this.y = y;
    		this.image = image;
    	}
    	
    	
    	
    	public void drawObject(Graphics g){
    		g.drawImage(image, x, y, null);
    	}
    }
    Java Code:
    import java.applet.Applet;
    
    public class RepaintThread extends Thread {
    
        private boolean mRun = false;
        Applet applet;
        
        public RepaintThread(Applet app) {
        	this.applet = app;
        }
     
        public void setRunning(boolean run) {
            mRun = run;
        }
     
        @Override
        public void run() {
        	long waitTime = (long)((1.0 / 60.0) * 1000);
    
            while (mRun) {
            
            	long last = System.currentTimeMillis();
                applet.repaint();
                
                long usedTime = System.currentTimeMillis()- last ;
                
                try {
                	
                	long realWaitTime = waitTime - usedTime;
    				Thread.sleep(Math.max(0, realWaitTime));
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
            }
        }
    }
    The image I used "icon.jpg" is a 72x72 image. The method paint is without double buffered drawing and could draw roughly 40000 objects before hitting my "cpu-cap". The method paint2 is with double buffering and could draw roughly 40 objects before hitting my "cpu-cap"

  4. #4
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,421
    Rep Power
    25

    Default

    What is supposed to happen when I execute the code?
    Can I run it in Appletviewer to see what happens?
    Or does it need to be run in a browser?

    Java Code:
                long last = System.currentTimeMillis();
                applet.repaint();
                
                long usedTime = System.currentTimeMillis()- last ;
    What is this code supposed to do? repaint() doesn't do the painting, it requests that a call be made to the paint method.
    Last edited by Norm; 07-18-2011 at 07:32 PM.

  5. #5
    Macpwnage is offline Member
    Join Date
    Jul 2011
    Posts
    5
    Rep Power
    0

    Default

    I'm sorry I'm not sure how to run this thing other than just copy-pasting the code into an IDE like Eclipse. :S
    On what is supposed to happen: it's just going to draw a whole bunch of images (all "icon.jpg") to the screen and depending on if you use the paint() or paint2() method it could increase your room temperature by quite a bit at even a relatively really low number of images (I could draw roughly 1000 times more images by just drawing to a different Graphics object). I can't figure out why this is, as I fail to see the real difference between the graphics object in paint method 1 and 2.

  6. #6
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,421
    Rep Power
    25

    Default

    I tested it in AppletViewer. The non buffered one put CPU% at 92 and flickered. The buffered one put CPU% at 98

    Is drawing 4000 images every 16/1000 of a second your usual way to draw images?

  7. #7
    Macpwnage is offline Member
    Join Date
    Jul 2011
    Posts
    5
    Rep Power
    0

    Default

    Well no, normally it would be a lot less images; however using my own tests I could only reach about 40 images (edit:without the loss of frames) (not 4000 (if you could change the number of images you could probably see that you would reach that 98% at way fewer images than 4000)) buffered which seems way too low and I therefore concluded that I'm doing something wrong/awfully inefficient right now which could probably be done in a much better way. I realise that reducing the number of frames /second would help a lot however there has to be something else that I could do to double buffer without having a limit of 40 small images in a game.


    if you could add the following to the DrawnObject's drawObject(Graphics g) method you could see how it is not actually drawing 4k objects every 16/1000 th second if you use the double buffering
    Java Code:
    x+=(Math.random()-0.5) *100;
    Last edited by Macpwnage; 07-18-2011 at 08:29 PM.

  8. #8
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,421
    Rep Power
    25

    Default

    Just ran two tests and got: CPU @ 80% with 400 images, 30% with 100 images

    you could see how it is not actually drawing 4k objects every 16/1000 th second if you use the double buffering
    There are a lot of images. How do you know how many are drawn how fast?

  9. #9
    Macpwnage is offline Member
    Join Date
    Jul 2011
    Posts
    5
    Rep Power
    0

    Default

    Quote Originally Posted by Norm View Post
    There are a lot of images. How do you know how many are drawn how fast?
    Well I don't know how many are drawn but I can be certain that they are not drawn at the right speed considering it takes over a second (at 4000 objects ) for anything to change between frames with double buffering (without it it seems like things are updating all the time (which I assume means every ~16 ms).

Similar Threads

  1. Help with double Buffering
    By Kyle227 in forum AWT / Swing
    Replies: 1
    Last Post: 10-26-2010, 09:08 PM
  2. Double Buffering an Application?
    By Moncleared in forum New To Java
    Replies: 8
    Last Post: 09-14-2009, 04:45 AM
  3. Double Buffering
    By dunff2k in forum SWT / JFace
    Replies: 1
    Last Post: 11-14-2008, 03:26 PM
  4. [SOLVED] Double Buffering
    By Zosden in forum AWT / Swing
    Replies: 1
    Last Post: 07-24-2008, 02:28 AM
  5. Double Buffering problem
    By aprenz in forum Java Applets
    Replies: 0
    Last Post: 05-28-2008, 04:26 AM

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •