Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (109)
games submitted by our members
Games in WIP (536)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Benchmark: BufferStrategy vs double buffering via .drawImage()  (Read 2224 times)
0 Members and 1 Guest are viewing this topic.
Offline Kova

Senior Member





« Posted 2006-10-24 17:38:17 »

So I was using double buffering by manually drawing everything to offscreen image and then drawing that image on screen. Now I deceided to use swing in my game and convert rendering code to use buffer strategy. For activly rendering swing I used stuff described here.
After putting it all together I noticed drop of fps on my slower computer from 55 to 44. I was very dissapointed becouse I was actually expecting fps increase as I heard that double buffering uses all avaliable speed up methodes. So to check if it was from converting to buffer stragegy I created a small benchmark similar to my game rendering engine.
For test I drawed 100 ovals in a loop, 50 rectangles and 50 20x20 png images with alpha channel. Resoults are good, without png images BS rendering goes to 220 fps, and BI rendering only 90. With png images BS drops to 80, but it's still a lot better then 60 BI render gets. So conclusion of this small benchmark is this: BS rendering is noticablely faster then BI rendering, and extreamly faster when dealing with java shapes.
This is my first benchmark test so don't take it too seriously and if you see any bugs or improper measuring please tell. Why fps droped down in my game... I don't know, probably becouse synchronizing for being able to render swing components. This is what I'll test next.

Here is the code, 2 classes, switch rendering mode by setting "BS" or "BI" in VitkroijePanel.RENDER_METHOD :

Viktorije:
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  
package viktorije;

import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;

public class Viktorije extends JFrame {

   public final static int DEFAULT_FPS = 60;
   
   public static int res_height;
   public static int res_width;
   
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////  
 
   // MAIN
  public static void main(String[] args) {
      int fps = DEFAULT_FPS;
       long period = (long) 1000.0/fps;
       System.out.println("fps: " + fps + "; period: " + period + " ms");
       new Viktorije("Viktorije", period*1000000L);     // ms --> nanosecs
  }
   
   // CONSTRUCTOR
  public Viktorije(String title, long period) {
      super(title);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setIgnoreRepaint(true);
      setUndecorated(false);
      Dimension screen_dim = Toolkit.getDefaultToolkit().getScreenSize();
      res_width = (int)screen_dim.getWidth();
      res_height = (int)screen_dim.getHeight();
      setBounds(0,0,res_width,res_height);
      setResizable(false);

      setVisible(true);   // must be called before createBufferStrategy() or exception is thrown, don't know why
     createBufferStrategy(2);
       
      ViktorijePanel viktorije_panel = new ViktorijePanel(this, period);
      setContentPane(viktorije_panel);
     
      viktorije_panel.startAnim();      // Kova: starts game loop thread
  }

}


ViktorijePanel:
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  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
168  
169  
170  
171  
172  
173  
174  
175  
176  
177  
178  
179  
180  
181  
182  
183  
184  
185  
186  
187  
188  
189  
190  
191  
192  
193  
194  
195  
196  
197  
198  
199  
200  
201  
202  
203  
204  
205  
206  
207  
208  
209  
210  
211  
212  
213  
214  
215  
216  
217  
218  
package viktorije;

import java.awt.*;
import java.awt.image.*;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class ViktorijePanel extends JPanel implements Runnable {
   
   private Thread animator;  
   
   private volatile boolean running = false;
    private long used_time = 0;
    private int[] fps_store = new int[50];
    private int fps = 0;
    private int j = 0;
    private static final String RENDER_METHOD = "BI"; // Kova: if not BS it will assume BI
   private Graphics dbg;
    private Image dbImage;
   
   private GraphicsDevice device;
   private DisplayMode display_mode;
   private BufferStrategy buffer_strategy;
   private Viktorije viktorije;
   
//    BufferedImage ball = loadImage("images/lopta_1.png");
 
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////

   // CONSTRUCTOR
  public ViktorijePanel(Viktorije viktorije, long period) {
      this.viktorije = viktorije;
      this.buffer_strategy = viktorije.getBufferStrategy();
      setSize(1024,768);
      setIgnoreRepaint(true);
      setOpaque(true);
       setLayout(null);
   }  // end: constructor
 
   public void paint(Graphics g) {
      System.out.println("ViktorijePanel.paint(): this should rarely (best never) be called");
   }
   
   // Kova: create and start main game thread
  public void startAnim() {
      if (animator == null || !running) {
           animator = new Thread(this, "Viktorije Animator");
           animator.start();
      }
   } // kraj: startAnim()

   // Kova: start main game thread
  public void run() {
       running = true;
       GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
       device = environment.getDefaultScreenDevice();
       display_mode = new DisplayMode(1024,768,32,DisplayMode.REFRESH_RATE_UNKNOWN);
       System.out.println("device.isFullScreenSupported() == " + device.isFullScreenSupported());

       while(running) {
            long start_time = System.nanoTime();
         
            if (RENDER_METHOD.equals("BI")) {
                gameRenderBI();
                paintScreenBI();                
            } else {
                gameRenderBS();
                paintScreenBS();                
            }

           sleep();
           
            used_time = System.nanoTime() - start_time;
            fps_store[j] = 1000/(int)(used_time/1000000);
            j++;
            if (j>49) j=0;
            fps = 0;
            for (int fps1: fps_store) {
                fps += fps1;
            }
            fps /= 50;
       }
       
   } // end: run()

    // Kova: only yields
  private void sleep() {
//      try {
//         Thread.sleep(10);   // Kova: 100 fps
//        } catch (InterruptedException e) {
//           e.printStackTrace();
//        }
       Thread.yield();
   }

   // Kova: load images for testing if you like...
   public static BufferedImage loadImage(String path) {
       URL url = null;
        try {
           url = Viktorije.class.getClassLoader().getResource(path);
            return ImageIO.read(url);
        } catch (Exception e) {
           System.out.println("Error loading image: " + path + " " + url);
           System.exit(0);
           return null;
        }
    }

    // Kova: render graphics using BufferStrategy
   private void gameRenderBS() {
      Graphics2D g2d = null;
      g2d = (Graphics2D)buffer_strategy.getDrawGraphics();  
      drawMyStuff(g2d);
   }

    // Kova: paint using BufferStrategy
  private void paintScreenBS() {
       try {
          buffer_strategy.show();
           Toolkit.getDefaultToolkit().sync();                 // Sync the display on some systems (on Linux, this fixes event queue problems)
      }
       catch (Exception e) { // quite commonly seen at applet destruction
         System.out.println("Graphics error: " + e);
          e.printStackTrace();
       }
   } // end of paintScreen()

    // Kova: render graphics using offscreen BufferedImage
   private void gameRenderBI() {
        if (dbImage == null) {
            dbImage = createImage(1024, 768);
            if (dbImage == null) {
                return;
            }
            dbg = dbImage.getGraphics();
        }
        drawMyStuff(dbg);
    }
   
    // Kova: paint using .drawImage() using BufferedImage as offscreen buffer
   private void paintScreenBI() {
        Graphics g;
        try {
            g = this.getGraphics();
            if ((g != null) && (dbImage != null))
                g.drawImage(dbImage, 0, 0, null);
            Toolkit.getDefaultToolkit().sync();
            g.dispose();
        }
        catch (Exception e) {
            System.out.println("Graphics error: " + e);  
        }
    }
   
   public void setFullScreen(boolean fullScreen) throws IllegalArgumentException {
      if (isFullScreen() == fullScreen) {
         return;            // CommanderKeith: we're already in fullscreen, so return.
     }
      if (fullScreen) {
         viktorije.setResizable(false);
         device.setFullScreenWindow(viktorije);
         if (display_mode != null && device.isDisplayChangeSupported()) {
            try {
               device.setDisplayMode(display_mode);
               System.out.println("display mode set");
            } catch (IllegalArgumentException e) {
               System.out.println("display mode not supported");
               device.setFullScreenWindow(null);
               viktorije.setResizable(true);
               throw e;
            }
         } else {
            device.setFullScreenWindow(null);
            viktorije.setResizable(true);
            throw new IllegalArgumentException("device.isDisplayChangeSupported() == false");
         }
      } else {
         device.setFullScreenWindow(null);
         viktorije.setResizable(true);
      }
      viktorije.createBufferStrategy(2);
      this.buffer_strategy = viktorije.getBufferStrategy();
   }
   
   public boolean isFullScreen() {
      if (device.getFullScreenWindow() == null){
         return false;
      }
      return true;
   }

    // Kova: draw your stuff for testing
   private void drawMyStuff(Graphics g) {
        g.setFont(new Font("Arial", Font.BOLD, 18));
        g.drawString(RENDER_METHOD, 20, 70);
        g.setColor(Color.GREEN);
        g.fillRect(0, 0, Viktorije.res_width, Viktorije.res_height);      // Kova: clear the background

        g.setColor(Color.white);
        g.fillRect(0, 45, Viktorije.res_width, 6);    
   
        for (int i=0; i<50; i++) {
            g.drawOval(10*i, 10*i, 50, 50);
            g.drawOval(10*i, 768/(i+1), 50, 50);
            g.fillRect(10*i, 500, 50, 50);
//            g.drawImage(ball, 20*i, 600, null);
       }
        g.setColor(Color.BLACK);
        g.drawString("say: ", 25, 725);

        if (used_time > 0) {
            g.drawString("FPS: " + fps, 20, 40);
        }
    }

}  // end: ViktorijePanel
Online CommanderKeith
« Reply #1 - Posted 2006-10-25 06:06:18 »

That's weird, in window mode BufferStrategy & manual double-buffering with images should be the same.  The reason may be because your BufferedImages aren't accelerated until they are copied a couple of times, so they'd be slower at the start.  If you used VolatileImages there wouldn't be this slow down, but its not a big deal since its only at the start.

In full screen mode BufferStrategy is likely to be a lot faster since it can use a flip strategy (pointer shifting) rather than blitting (copying pixels).

Anti-aliasing those circles will probably have a big affect on performance too.

Keith

Offline Kova

Senior Member





« Reply #2 - Posted 2006-10-25 17:04:51 »

That's weird, in window mode BufferStrategy & manual double-buffering with images should be the same.  The reason may be because your BufferedImages aren't accelerated until they are copied a couple of times, so they'd be slower at the start.  If you used VolatileImages there wouldn't be this slow down, but its not a big deal since its only at the start.

What do you mean only at start? Start is the first frame, every other should be accelarated, so I've read somewhere... but it dosen't even matter since my 20x20 image has alpha channel and isn't surely accelarated under windows (default directdraw).

In full screen mode BufferStrategy is likely to be a lot faster since it can use a flip strategy (pointer shifting) rather than blitting (copying pixels).

flip strategy only becomes avaliable in full screen? Ah, didn't know that, I'll test in full screen also.

Anti-aliasing those circles will probably have a big affect on performance too.

don't know if aa is automaticly on or off, but I didn't change a thing so my draw method should be the same weight for both rendering methodes.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

CogWheelz (18 views)
2014-07-30 21:08:39

Riven (26 views)
2014-07-29 18:09:19

Riven (15 views)
2014-07-29 18:08:52

Dwinin (13 views)
2014-07-29 10:59:34

E.R. Fleming (34 views)
2014-07-29 03:07:13

E.R. Fleming (12 views)
2014-07-29 03:06:25

pw (43 views)
2014-07-24 01:59:36

Riven (44 views)
2014-07-23 21:16:32

Riven (30 views)
2014-07-23 21:07:15

Riven (31 views)
2014-07-23 20:56:16
List of Learning Resources
by SilverTiger
2014-07-31 18:29:50

List of Learning Resources
by SilverTiger
2014-07-31 18:26:06

List of Learning Resources
by SilverTiger
2014-07-31 13:54:12

HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!