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  
  Volatile vs Buffered  (Read 3099 times)
0 Members and 1 Guest are viewing this topic.
Offline crazyc94

Senior Newbie




I like cheese


« Posted 2006-01-10 01:41:31 »

I'm writing a small Asteroids clone (Stroids  Cool), and on my first slightly playable build, I noticed that my graphics were lagging something horrible.  So I logged on here, looked around, and noticed that VolatileImage is recommended for doing graphics.  I was using BufferedImage and Graphics.drawImage(buffered, x, y, null), so I thought the volatile might work better.

So I wrote a simple class today and tested it.  And much to my astonishment, BufferedImage is outperforming VolatileImage ( Shocked).  This doesn't make sense except that I have onboard video so there may be some hidden optimization.  What I'm wondering is if anyone can spot something I did wrong in this test.

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  
public class Form extends JFrame imple....
    ...
    private BufferedImage buffered1;
    private BufferedImage buffered2;
    private VolatileImage volatile1;
    private VolatileImage volatile2;
    private VolatileImage comp;
    private javax.swing.Timer timer;

public Form()
    {
        super();
       
        setSize(800, 800); //This is the same size Stroids uses
       
        setVisible(true);
       
        //Load the buffered images
       try {
            buffered1 = ImageIO.read(new File("img1.png"));
            buffered2 = ImageIO.read(new File("img2.png"));
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        ...

        x = 0; //Initalize the scrolling variables
       y = 0;
        timer = new javax.swing.Timer(30, this); //Create a timer to cause a repaint every 30 ms
       
        timer.start(); //Start the timer
   }

/*
 * One or more of the VolatileImages needs to be re-created, or created the first time
*/

private void restoreVolatiles()
    {
        if (volatile1 == null) //No image
           volatile1 = createVolatileImage(800, 800); //Create the image
       
        if (volatile2 == null) //No image
           volatile2 = createVolatileImage(20, 20); //Create the image
       
        if (comp == null) //No image (used for off-screen rendering)
           comp = createVolatileImage(800, 800); //Create the image
       
        Graphics g;
        if (volatile1.validate(getGraphicsConfiguration()) != VolatileImage.IMAGE_OK) //Not ok, so redraw it
       {
            g = volatile1.getGraphics();
            g.drawImage(buffered1, 0, 0, this);
        }
       
        if (volatile2.validate(getGraphicsConfiguration()) != VolatileImage.IMAGE_OK) //Not ok, so redraw it
       {
            g = volatile2.getGraphics();
            g.drawImage(buffered2, 0, 0, this);
        }
    }

public void paintComponent(Graphics _g2)
    {
        Graphics2D g2 = (Graphics2D)_g2;
       
        long volatileDuration, bufferedDuration; //Used to determine how long rendering takes
       
        long startNano = System.nanoTime(); //Get the start time
       
        if (volatile1 == null || volatile2 == null ||
                volatile1.validate(getGraphicsConfiguration()) != VolatileImage.IMAGE_OK || volatile2.validate(getGraphicsConfiguration()) != VolatileImage.IMAGE_OK)
        { //Check if anything needs to be fixed (always runs on first time through: volatile1 == null)
           restoreVolatiles(); //Restore the volatiles
       }
       
        Graphics2D g = comp.createGraphics(); //Get the graphics to composite it
       
        g.drawImage(volatile1, 0, 0, this); //Draw the background (big, 800x800)
       
        g.drawImage(volatile2, x, y, this); //Draw the random image (small, 20x20)
       
        g2.drawImage(comp, 0, 0, this); //Copy to the screen (big 800x800)
       
        volatileDuration = System.nanoTime() - startNano; //Get the time taken
       
        startNano = System.nanoTime(); //Get the start time
       
        g2.drawImage(buffered1, 0, 0, this); //Draw the background
       
        g2.drawImage(buffered2, x, y, this); //Draw the random image
       
        bufferedDuration = System.nanoTime() - startNano; //Get the end time
       
        //Now print out the stats
       try
        { //writer is initalized in the constructor, and is a FileWriter
           System.out.println("Buffered draw took " + bufferedDuration / 1000000.0 + " ms.");
            writer.write("Buffered draw took " + bufferedDuration / 1000000.0 + " ms.\n");
            System.out.println("Volatile draw took " + volatileDuration / 1000000.0 + " ms.");
            writer.write("Volatile draw took " + volatileDuration / 1000000.0 + " ms.\n");
            System.out.println("Volatile was faster by " + (bufferedDuration - volatileDuration) / 1000000.0 + " ms.");
            writer.write("Volatile was faster by " + (bufferedDuration - volatileDuration) / 1000000.0 + " ms.\n");
           
            writer.flush();
           
        } catch (IOException ex)
        {
            ex.printStackTrace();
        }
    }
}


The file that writer prints to gives this (only an excerpt):

Quote
Buffered draw took 0.058667 ms.
Volatile draw took 0.118451 ms.
Volatile was faster by -0.059784 ms.
Buffered draw took 0.060064 ms.
Volatile draw took 0.111466 ms.
Volatile was faster by -0.051402 ms.
Buffered draw took 0.059225 ms.
Volatile draw took 0.136889 ms.
Volatile was faster by -0.077664 ms.
Buffered draw took 0.059225 ms.
Volatile draw took 0.135213 ms.
Volatile was faster by -0.075988 ms.
Buffered draw took 0.056432 ms.
Volatile draw took 0.143874 ms.
Volatile was faster by -0.087442 ms.
Buffered draw took 0.059784 ms.
Volatile draw took 0.137168 ms.
Volatile was faster by -0.077384 ms.
Buffered draw took 0.062019 ms.
Volatile draw took 0.137168 ms.
Volatile was faster by -0.075149 ms.

I am missing something?  Is my rendering strategy off?  Or do I just need to render many more images per cycle to see the difference?  Huh

Quack!  I'm a duck!

"Or make your own RationalNumber class (unless you need irrational numbers, then you're screwed )." - shmoove
Offline crazyc94

Senior Newbie




I like cheese


« Reply #1 - Posted 2006-01-10 01:57:03 »

I just made a slight change to it to see if rendering an image multiple times (the small 20x20 100 times instead of 1) would have an effect.  It does:

Quote
Buffered draw took 159.936807 ms.
Volatile draw took 364.469227 ms.
Volatile was faster by -204.53242 ms.
Total volatile faster by -204.53242 ms.
Buffered draw took 1.946337 ms.
Volatile draw took 10.244318 ms.
Volatile was faster by -8.297981 ms.
Total volatile faster by -212.830401 ms.
Buffered draw took 1.737651 ms.
Volatile draw took 10.188725 ms.
Volatile was faster by -8.451074 ms.
Total volatile faster by -221.281475 ms.
Buffered draw took 1.739048 ms.
Volatile draw took 1.656356 ms.
Volatile was faster by 0.082692 ms.
Total volatile faster by -221.198783 ms.
Buffered draw took 2.647823 ms.
Volatile draw took 1.361904 ms.
Volatile was faster by 1.285919 ms.
Total volatile faster by -219.91286399999998 ms.
Buffered draw took 1.922311 ms.
Volatile draw took 1.377829 ms.
Volatile was faster by 0.544482 ms.
Total volatile faster by -219.368382 ms.
Buffered draw took 2.191898 ms.
Volatile draw took 1.339835 ms.
Volatile was faster by 0.852063 ms.
Total volatile faster by -218.516319 ms.

It seems now that the major time consuming task is copying the image data from the buffered images to the volatile image.

Quack!  I'm a duck!

"Or make your own RationalNumber class (unless you need irrational numbers, then you're screwed )." - shmoove
Offline trembovetski

Senior Member




If only I knew what I'm talking about!


« Reply #2 - Posted 2006-01-11 01:39:30 »

The idea is to use BufferedImages (they're all acceleratable as of 1.5) for your sprites, and
VolatileImage (or BufferStrategy) for your back-buffer.

This article may help:
  http://weblogs.java.net/blog/chet/archive/2004/08/toolkitbuffered.html

The problem is when your sprite is translucent (as opposed to 1-bit transparent or opaque) -
the translucent images aren't accelerated unless you use the non-default OpenGL pipeline.

Thanks,
  Dmitri
Java2D Team
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline crazyc94

Senior Newbie




I like cheese


« Reply #3 - Posted 2006-01-11 04:37:44 »

Ah.  Now it makes sense  Cheesy

Thanks for the very helpful link  Smiley

Quack!  I'm a duck!

"Or make your own RationalNumber class (unless you need irrational numbers, then you're screwed )." - shmoove
Offline TheAnalogKid

JGO Coder


Projects: 2



« Reply #4 - Posted 2006-01-11 16:58:56 »

All those useful blogs should centralized and accessible via the Java Games home page or the games wiki page.

Offline pepe

Junior Member




Nothing unreal exists


« Reply #5 - Posted 2006-01-11 17:20:43 »

The problem is when your sprite is translucent (as opposed to 1-bit transparent or opaque) -
the translucent images aren't accelerated unless you use the non-default OpenGL pipeline.
Are they accelerated under 1.6 by default?
I must admit that i was already pretty surprised by the perfs for translucent transformed blits in 1.5, so i thought they were somewhat accelerated.
Under 1.6, my graphical test got some more acceleration, but not much enough to say that hardware acceleration implementation for them was the cause of the difference (65 to 95/100fps).
But, it might be the case and i might have expected much more from my hardware than what i ought to.  Undecided

Home page: http://frederic.barachant.com
------------------------------------------------------
GoSub: java2D gamechmark http://frederic.barachant.com/GoSub/GoSub.jnlp
Offline Linuxhippy

Senior Member


Medals: 1


Java games rock!


« Reply #6 - Posted 2006-01-11 21:40:12 »

Are they accelerated under 1.6 by default?

No, a opengl-like Direct3d pipeline has been added which should support more boards than opengl does on windows (since hw manufacturers don't care about open protocolls and apis) but its disabled by default because of possible driver problems.

Quote
I must admit that i was already pretty surprised by the perfs for translucent transformed blits in 1.5, so i thought they were somewhat accelerated.
Under 1.6, my graphical test got some more acceleration, but not much enough to say that hardware acceleration implementation for them was the cause of the difference (65 to 95/100fps).
But, it might be the case and i might have expected much more from my hardware than what i ought to.  Undecided
By default translucent blits are done in software, sorry Wink (btw. as far as I know but I am maybe wrong)

lg Clemens
Offline trembovetski

Senior Member




If only I knew what I'm talking about!


« Reply #7 - Posted 2006-01-13 04:49:01 »

The problem is when your sprite is translucent (as opposed to 1-bit transparent or opaque) -
the translucent images aren't accelerated unless you use the non-default OpenGL pipeline.
Are they accelerated under 1.6 by default?
I must admit that i was already pretty surprised by the perfs for translucent transformed blits in 1.5, so i thought they were somewhat accelerated.
Under 1.6, my graphical test got some more acceleration, but not much enough to say that hardware acceleration implementation for them was the cause of the difference (65 to 95/100fps).
But, it might be the case and i might have expected much more from my hardware than what i ought to.  Undecided

We've done some work on optimizing the software transforms (although I thought we've done that
in 5.0, but there may be something else we done in 6.0 that I'm forgetting), that's probably why they're
fast.

In fact, the all-software rendering (like to a BufferedImage) can be surprisingly fast.
The stuff gets slow when you mix hw and sw operations (like in the case of alpha compositing to
a VolatileImage).

Dmitri
Offline HamsterofDeath

Junior Member




Java games rock!


« Reply #8 - Posted 2006-01-17 16:10:09 »

i did a few performance tests.

900 rotated & scaled images (this one -> http://www.kittysafe.net/gallery/data/media/4/evil_hamster.jpg), stored in a bufferedimage, copied to volatile
on java5, 1.8 ghz opteron, geforce 7800gt -> 1-2 fps, counted myself.
bufferdimage to bufferedimage -> ~0.25 fps, counted myself.
volatile to volatile -> ~0.25, again counted myself.
java6 using d3d-pipeline -> 250 fps, measured. (the test calculates the fps every 100 frames, so this was the only one actually giving me numbers)
opengl should be around 250 fps, too.

i'll upload the hamster rotate test when i'm back home.
Offline trembovetski

Senior Member




If only I knew what I'm talking about!


« Reply #9 - Posted 2006-01-18 05:00:48 »

Quote

Wow! That's one evil hampster! Can I have it as my avatar? =)

Dmitri
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline HamsterofDeath

Junior Member




Java games rock!


« Reply #10 - Posted 2006-01-19 19:12:50 »

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  
/* Copyright Hamster Development 2006 */
package src;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.DisplayMode;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.Window;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Developed with pleasure :)
 *
 * @author HamsterofDeath
 */

public class SpinBench extends JFrame
{
// ------------------------------ FIELDS ------------------------------

  public static SpinBench instance;
  private JPanel jpMain;

  private String title;

// --------------------------- CONSTRUCTORS ---------------------------

  /**
   * Standard-konstruktor
   */

  public SpinBench(Image img)
  {
    super();
    instance = this;
    this.title = "Spinbench";
    setResizable(false);
    buildGUI();
    addListener();
    pack();
    center();

    Window w = new Window(this);
    getGraphicsConfiguration().getDevice().setFullScreenWindow(w);
    getGraphicsConfiguration().getDevice().setDisplayMode(new DisplayMode(1600, 1200, 32, 60));
    Image buffered = getImg();
    Graphics2D graphics;
    List<Graphics2D> g2d = new ArrayList<Graphics2D>();
    for (int i = 1; i < 31; i++)
    {
      for (int i2 = 1; i2 < 31; i2++)
      {
        Graphics2D g2 = (Graphics2D) buffered.getGraphics();
        g2.translate(i * 50, i2 * 50);
        g2.scale(0.1, 0.1);
        g2d.add(g2);
        //g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
       //g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
     }
    }
    graphics = (Graphics2D) buffered.getGraphics();
    graphics.setColor(Color.black);
    while (true)
    {
      long startTime = System.nanoTime();
      int frames = 0;
      while (frames++ < 100)
      {
        graphics.fillRect(0, 0, 1600, 1200);
        for (Graphics2D graphics2D : g2d)
        {
          graphics2D.rotate(0.1 * Math.random());
          graphics2D.drawImage(img, 0, 0, null);
        }
        //aufs panel
       w.getGraphics().drawImage(buffered, 0, 0, null);
      }
      long elapsed = System.nanoTime() - startTime;
      double nsPerDraw = elapsed / (float) frames;
      System.out.println(nsPerDraw + " ns per frame = " + 1.0 / (nsPerDraw / 1000000000.0) + " fps");
    }
  }

  private Image getImg()
  {
    //  return new BufferedImage(1600, 1200, BufferedImage.TYPE_INT_ARGB);
   return this.createVolatileImage(1600, 1200);
  }

  /**
   * Gui aufbauen
   */

  protected void buildGUI()
  {
    setTitle(title);
    getContentPane().setLayout(new BorderLayout(6, 6));
    jpMain = new JPanel();
    getContentPane().add(jpMain, BorderLayout.CENTER);
    jpMain.setBorder(new EmptyBorder(6, 6, 6, 6));
    jpMain.setLayout(new BorderLayout(6, 6));

    jpMain.setPreferredSize(new Dimension(640, 480));
  }

  /**
   * Listener registrieren
   */

  protected void addListener()
  {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  }

  private void center()
  {
    Toolkit tk = Toolkit.getDefaultToolkit();
    setLocation((int) (tk.getScreenSize().getWidth() / 2 - getWidth() / 2),
                (int) (tk.getScreenSize().getHeight() / 2 - getHeight() / 2));
    setVisible(true);
  }

// --------------------------- main() method ---------------------------

  public static void main(String[] args)
    throws IOException
  {
    Image image = ImageIO.read(new File("resource/hamster.jpg"));
    new SpinBench(image);
  }
}
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 (12 views)
2014-08-01 22:53:16

CogWheelz (14 views)
2014-08-01 22:51:43

CopyableCougar4 (15 views)
2014-08-01 19:37:19

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

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

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

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

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

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

pw (44 views)
2014-07-24 01:59:36
Resources for WIP games
by CogWheelz
2014-08-01 18:20:17

Resources for WIP games
by CogWheelz
2014-08-01 18:19:50

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
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!