Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (499)
Games in Android Showcase (118)
games submitted by our members
Games in WIP (568)
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  
  Accelerating images through BufferStrategy  (Read 9057 times)
0 Members and 1 Guest are viewing this topic.
Offline The 11th plague of Egypt

Senior Newbie


Medals: 1



« Posted 2011-12-04 21:40:07 »

I need to draw on screen the same images many times, so I'm trying to accelerate it.

Every tutorial on acceleration I've seen so far uses a BufferedStrategy, inside a Canvas, inside a Frame.

But I can't find a simple tutorial that draws an accelerated image onto that Canvas.

I'd just draw a VolatileImage on the canvas, but I guess that would defeat the purpose of the BufferedStrategy.

Also, I can't figure out how to validate both the VolatileImage and the BufferedStrategy.
I guess they would interfere as they both call dispose() on the Graphics object.

I've seen this tutorials so far:

- this one never seems to validate the images
http://www.cokeandcode.com/info/tut2d.html

- this one doesn't load images, but is much clearer
http://www.javalobby.org/forums/thread.jspa?threadID=16867&tstart=0

EDIT: this one seems interesting too, but I think there's a little odd on the comment "This should not happen"
http://www.exampledepot.com/egs/java.awt.image/VolImage.html

Also, only the first tutorial use setIgnoreRepaint(true);

I'd like to edit the second tutorial making it draw a .gif image loaded from outside,
what's the best way to do that?

BTW I'd like to allow the user to resize the window, if that's possible
Offline ra4king

JGO Kernel


Medals: 347
Projects: 3
Exp: 5 years


I'm the King!


« Reply #1 - Posted 2011-12-04 22:52:07 »

The best way is just to create compatible images (look at line 87) and avoid VolatileImage.

GIF images are not supported well in Java2D.

Resizing is always possible. Smiley

Offline The 11th plague of Egypt

Senior Newbie


Medals: 1



« Reply #2 - Posted 2011-12-04 23:38:23 »

Thanks, if a BufferedImage can be accelerated as well, I'll gladly avoid using VolatileImage(s).

I'll try to make an example and post here for review.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline delt0r

JGO Knight


Medals: 27
Exp: 18 years


Computers can do that?


« Reply #3 - Posted 2011-12-05 10:15:57 »

The problem with java2d is that it can very easily fall back to software rendering. And the software java2d rendering pipeline is really slow. So you get particularly slow software rendering without doing anything "wrong".

Basically don't rotate, don't scale, only use bit alpha channel, don't use AA, use compatible image pixel/colour formats. With all that you have good odds of getting some HW acceleration.

But i have noticed that java2d is really pretty poor for this sort of thing. Its fine for gui's that don't need to draw whole thing every frame, but once you are doing animations or games its a very poor match. I would recommend looking into using lwjgl or slick or something to get anything like real consistent performance.

I have no special talents. I am only passionately curious.--Albert Einstein
Offline The 11th plague of Egypt

Senior Newbie


Medals: 1



« Reply #4 - Posted 2011-12-05 22:25:40 »

Agree, Swing sucks, but still, it's the standard library, so I'm just trying to learn the basics before moving on.

I finished my example, I modded the tutorial I posted, and another one too.

Here are my 2 classes. Do you know of a (quick) way to fix the flickering when resizing the window?
Because it look really awful, and I don't want to force a fixed size.
Here's my whole Eclipse project.

BTW I guess I also need to interrupt the thread when the frame closes, but fixing the resize takes priority now

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  
package sandbox;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Transparency;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class MyGame {
   private static final int FRAME_DELAY = 20; // 20ms. implies 50fps (1000/20) = 50

   public MyGame() {
      System.out.println(this.getClass().getClassLoader().getResource("resources/smile.gif"));
     
      JFrame frame = new JFrame();
      JPanel myPanel = new JPanel();
      Canvas myCanvas = new Canvas();
//      myCanvas.setIgnoreRepaint(true); // Doesn't seem to work at all
     
      BorderLayout myBLayout = new BorderLayout();
      myPanel.setLayout(myBLayout);
      myPanel.add(myCanvas, BorderLayout.CENTER);
      myPanel.add(new JButton("Clicky"), BorderLayout.EAST);
     
      frame.setContentPane(myPanel);
      frame.setSize(500, 500);
      frame.setVisible(true); // start AWT painting.
     
      Thread gameThread = new Thread(new GameLoop(myCanvas));
      gameThread.setPriority(Thread.MIN_PRIORITY);
      gameThread.start(); // start Game processing.
  }
   
   public static void main(String[] args) {
      MyGame myGame = new MyGame();
   }
 
   private static class GameLoop implements Runnable {
 
      boolean isRunning;
      Canvas myCanvas;
      long cycleTime;
      int moveX = 0;
      int moveY = 0;
     
      ImageLoader myImageLoader = new ImageLoader(null);
      BufferedImage myImage = myImageLoader.loadImage("resources/smile.gif", Transparency.TRANSLUCENT);
 
      public GameLoop(Canvas canvas) {
         myCanvas = canvas;
         isRunning = true;
      }
 
      public void run() {
         cycleTime = System.currentTimeMillis();
         myCanvas.createBufferStrategy(2);
         BufferStrategy strategy = myCanvas.getBufferStrategy();
 
         // Game Loop
        while (isRunning) {
 
            updateGameState();
 
            updatemyCanvas(strategy);
 
            synchFramerate();
         }
      }
 
      private void updateGameState() {
         // Nothing to do right now
     }
 
      private void updatemyCanvas(BufferStrategy strategy) {
         Graphics g = strategy.getDrawGraphics();
 
         g.setColor(Color.WHITE);
         g.fillRect(0, 0, myCanvas.getWidth(), myCanvas.getHeight());
         g.setColor(Color.BLACK);
 
         moveX = (moveX + 8)%myCanvas.getWidth();
         moveY = (moveY + 8)%myCanvas.getHeight();
         for(int i = 0; i < 5; ++i) {
            g.drawImage(myImage, (int) (i*5 + moveX), (int) (i*5 + moveY), null);
         }
         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();
         }
      }
 
   }
}


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  
package sandbox;

import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.Hashtable;

import javax.imageio.ImageIO;

public class ImageLoader {
   final GraphicsConfiguration gc;
   private Hashtable<String, BufferedImage> chache = new Hashtable<String, BufferedImage>();

   public ImageLoader(GraphicsConfiguration gc) {
      if (gc == null) {
         gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
               .getDefaultScreenDevice().getDefaultConfiguration();
      }
      this.gc = gc;
   }

   public BufferedImage loadImage(String resource, int transparencyType) {
      try {
         if (chache.get(resource) != null) {
            return chache.get(resource);
         } else {
            URL imageURL = this.getClass().getClassLoader().getResource(resource);
            BufferedImage src = ImageIO.read(imageURL);
            // Images returned from ImageIO are NOT managedImages
           // Therefore, we copy it into a ManagedImage
           BufferedImage dst = gc.createCompatibleImage(src.getWidth(),
                  src.getHeight(), transparencyType);
            Graphics2D g2d = dst.createGraphics();
            g2d.setComposite(AlphaComposite.Src);
            g2d.drawImage(src, 0, 0, null);
            g2d.dispose();
            chache.put(resource, dst);
            return dst;
         }
      } catch (java.io.IOException e) {
         System.err.println("Cannot find resource " + resource);
         return null;
      }
   }
}
Offline ra4king

JGO Kernel


Medals: 347
Projects: 3
Exp: 5 years


I'm the King!


« Reply #5 - Posted 2011-12-06 01:12:28 »

Swing isn't that terrible. The only thing plaguing it is its single-threaded design, but with good coding, it shouldn't be a problem.

Offline The 11th plague of Egypt

Senior Newbie


Medals: 1



« Reply #6 - Posted 2011-12-06 09:04:32 »

I still need a fix to the flickering resize...

Should I drop Canvas completely? And what for?
Offline theagentd
« Reply #7 - Posted 2011-12-06 09:35:58 »

Swing isn't that terrible. The only thing plaguing it is its single-threaded design, but with good coding, it shouldn't be a problem.
LWJGL (and OpenGL in general) is single-threaded, but it's still a lot better than Java2D, at least performance-wise.

Myomyomyo.
Offline delt0r

JGO Knight


Medals: 27
Exp: 18 years


Computers can do that?


« Reply #8 - Posted 2011-12-06 10:48:31 »

Threads are overrated. It also has nothing to do with gui performance really. I have written snappy swing apps. There are slow C++ gui apps. But consistent performance with animation/games is not what java2d is really designed for. Regardless of what the engineers planed or claim. At the very least there would be somewhat reliable full screen modes and vsync if it was.

I have no special talents. I am only passionately curious.--Albert Einstein
Offline gimbal

JGO Knight


Medals: 25



« Reply #9 - Posted 2011-12-06 14:50:21 »

The problem with java2d is that it can very easily fall back to software rendering.

You say that as if it is a bad thing. A virtue of Java2D is that IF something cannot be hardware accelerated by the video hardware/drivers, it is no problem as Java2D will indeed use the software rendering techniques. It will be slower but at least you'll see -something-. This is not a problem of Java2D, it is a defining feature. Luckily nowadays you don't have to worry too much about that, video hardware and drivers are very mature so most of what you can do using Java2D (with the exception of some specific effects) can be hardware accelerated, even by Intel hardware.

Quote
And the software java2d rendering pipeline is really slow.

Again not true, unless you do things which are slow in any software rendering environment. Translucent transparency is a good example. When you do it properly it is actually quite fast. Of course there is some overhead because the tech is aimed at drawing flat user interfaces, not dynamic games. Most algorithms built into the Graphics object are optimized for accuracy, not performance. The Sun way of working around that was not to optimize what was already there, but to add new ways of doing it. For example there are multiple ways of performing scaling, ranging from dead slow to wicked fast.

Most of this is not a problem though, as in game development (using Java2D) your main weapon of choice is drawImage() anyway. The main thing to focus on is that images are accelerated, meaning they can stay in videomemory. Which is the case if it is a compatible image and you keep your fingers off of the underlying raster.

Quote
Basically don't rotate, don't scale, only use bit alpha channel, don't use AA, use compatible image pixel/colour formats. With all that you have good odds of getting some HW acceleration.

All true if you would recommend using the software rendering pipeline, but it has absolutely nothing to do with "getting hardware acceleration". These things mentioned here will not cause slowdowns IF you use the hardware rendering pipeline, as they are exactly the things that can be hardware accelerated (except for bit translucency; you should use translucent images in a hardware accelerated environment).
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline delt0r

JGO Knight


Medals: 27
Exp: 18 years


Computers can do that?


« Reply #10 - Posted 2011-12-06 15:04:03 »

Try it on more than your home machine. I am not making this up. Just check the threads here for example. Non bit alpha falls back to software rendering on everything i have tested as does AA and any image scaling that is not Nearest neighbor. The -Dsun.java2d.opengl=true|True results in very buggy output on my test platforms now as it did 6 years ago. Right now on linux you don't get any rendering at all! Rotation very quickly trips the very conservative HW acceleration in java2d easily as well, again i have seen this happen. Just asserting it didn't is not fixing the problem. Finally the java2d SW pipe line is slow. look at the source, is a large number of classes and calls that really make it hard work for the JIT and the GC, so you don't get any MMX/SSE acceleration. 

I have no special talents. I am only passionately curious.--Albert Einstein
Offline BoBear2681

JGO Coder


Medals: 18



« Reply #11 - Posted 2011-12-06 22:57:51 »

Swing isn't that terrible. The only thing plaguing it is its single-threaded design, but with good coding, it shouldn't be a problem.
LWJGL (and OpenGL in general) is single-threaded, but it's still a lot better than Java2D, at least performance-wise.

As is Win32, if I'm not mistaken.  My understanding is that virtually all (widely used) GUI toolkits are single-threaded.
Offline gimbal

JGO Knight


Medals: 25



« Reply #12 - Posted 2011-12-07 10:31:37 »

Try it on more than your home machine. I am not making this up. J

Neither am I, it performs very well on all machines I have used so far (gaming oriented machines) :/

What we can probably both agree on is that a major downside of Java2D is that because of all the plumbing built into it since its inception, you cannot depend on it performing the same on all machines. I believe the JDK6U10 changes made it a whole lot worse. I wonder if Prism of JavaFX2 can be a better alternative...
Offline javaKnight

Junior Newbie





« Reply #13 - Posted 2012-01-08 19:55:54 »

I also have a question about image acceleration and overall java2d performance.

I draw graphics by active rendering. It's nearly same everywhere - create JFrame with JPanel, set display mode, create buffer strategy and draw graphics. It's the way how the fullscreen application is made. When creating in window there is no need to change display mode and work with buffer strategy. When everything is done with screen display I normally create BufferedImages via GraphicsConfiguration.createCompatibleImage() to display.

Now is the thing that's really strange for me. I run application in window mode with frame rate counter. I do the same with fullscreen display mode and there is no change in frame rate. I always think that fullscreen mode has a really big advantage in processing images. I also add, that same thing is true for two other pc's around me. In each case frame rate still nearly the same.

So my question is, is it something wrong with code and me or is that the way that java handles graphics? If needed I can also paste some application's code with the way how the things are done. I highly appreciate any suggestions about this case.
Offline ra4king

JGO Kernel


Medals: 347
Projects: 3
Exp: 5 years


I'm the King!


« Reply #14 - Posted 2012-01-08 21:26:46 »

When going full screen, Java2D automatically v-syncs so you can never go more than 60FPS (or whatever Hz your screen displays at).

Also, how do you create a BufferStrategy? JPanel doesn't have an option to do so. Only Canvas and Window can. It is best to use a JFrame + Canvas and create the BufferStrategy on the Canvas.

Offline javaKnight

Junior Newbie





« Reply #15 - Posted 2012-01-08 23:04:58 »

Thanks for your quick reply.

I create a BufferStrategy from JFrame which object is my main window. Before that, I create JPanel where events and drawings are made and put it into frame. I tried to change JPanel into Canvas and create BufferStrategy from there, but drawing time didn't change and all events on JPanel stop working. I measure drawing time by using System.nanoTime() before and after main drawing function.
Offline ra4king

JGO Kernel


Medals: 347
Projects: 3
Exp: 5 years


I'm the King!


« Reply #16 - Posted 2012-01-08 23:09:54 »

Why are you worried about drawing time? As long as your screen is rendering at a reasonable framerate, you shouldn't be worrying.

Also, you shouldn't be using JPanel at all for events, add the listeners directly to the Canvas.

Offline javaKnight

Junior Newbie





« Reply #17 - Posted 2012-01-08 23:21:09 »

All keyboard event are binded to JFrame instance and all mouse event to JPanel.

It's seems really odd that there is no difference in drawing time between window mode and fullscreen mode at all.
Offline ra4king

JGO Kernel


Medals: 347
Projects: 3
Exp: 5 years


I'm the King!


« Reply #18 - Posted 2012-01-08 23:28:49 »

Why would you have listeners on different components?! Shocked
Put all listeners on the Canvas, nothing on the JFrame itself.

And why should there be an change? Your CPU/GPU doesn't get "faster" render things when in full screen.

Offline javaKnight

Junior Newbie





« Reply #19 - Posted 2012-01-08 23:40:16 »

Key listener is added to JFrame because there were problems with focus on JPanel, but for now it doesn't matter.

Now I even removed BufferStrategy at all and nothing changed. I read somewhere that all Swing components are default double buffered so it makes sense. In fullscreen mode there is access to many exclusive graphics card functions, so I thought that something is going to help to render faster.
Offline ra4king

JGO Kernel


Medals: 347
Projects: 3
Exp: 5 years


I'm the King!


« Reply #20 - Posted 2012-01-08 23:45:02 »

That's because JPanel isn't set to be focusable in the first place. You have to call JPanel.setFocusable(true) for it to receive focus.

Java2D is slow in either situation. "exclusive graphics card functions", I don't know about that one. Those "functions" you seek are low level DirectX/OpenGL functions which are not accessible to you through Java2D nor are they supposed to make anything go "faster".

I really suggest you stop worrying about tiny performance details like this. As I told you earlier, if your game/app runs at a reasonable framerate, STOP worrying and finish writing your game already! Grin

Offline theagentd
« Reply #21 - Posted 2012-01-09 00:06:53 »

And why should there be an change? Your CPU/GPU doesn't get "faster" render things when in full screen.
It's about exclusive fullscreen mode. There is a clear difference in performance between fullscreen and windowed, but I'm not sure if Java2D can actually enter exclusive mode. If it can then YES, fullscreen is faster.

Myomyomyo.
Offline javaKnight

Junior Newbie





« Reply #22 - Posted 2012-01-09 00:18:44 »

Thanks a lot for your time and effort Smiley

For now rendering all 2D tile map in resolution 640x480 takes about 3 ms, so I think it's quite good result and maybe it's true that I seek for too much performance boost in places where it cannot be granted Tongue Cpu usage for entire game takes 5-10% with 30fps on c2d processor, so there is much more to improvement  Wink

For example "Killer Game Programming in Java" calls it Full-Screen Exclusive Mode (FSEM) and it's done by invoking setDisplayMode(), but for what i can see there is no performance boost between it and window mode what's really strange for me.
Offline theagentd
« Reply #23 - Posted 2012-01-09 06:54:30 »

It's a really low-level thing, so it's probably the best that Java doesn't use it. I've had so much trouble with it (specifically ridiculous VM crashes on Intel graphics cards), so it's not really worth it anyway unless you're making a 3D game. That was with LWJGL though, which does use exclusive mode.

OT: To solve the crash I ended up creating an undecorated LWJGL window that was (width+2, height) to prevent automatic fullscreen just for Intel cards. Guess why I hate Intel?

Myomyomyo.
Offline ra4king

JGO Kernel


Medals: 347
Projects: 3
Exp: 5 years


I'm the King!


« Reply #24 - Posted 2012-01-09 17:51:43 »

Newer Intel integrated GPUs can now handle full screen Smiley

Offline theagentd
« Reply #25 - Posted 2012-01-09 18:42:02 »

Newer Intel integrated GPUs can now handle full screen Smiley
Wow. They can handle fullscreen. I guess that's one of their few selling points then. Maybe they'll be able to handle actual drawing someday too! I mean, faster than a software renderer.

Myomyomyo.
Offline BoBear2681

JGO Coder


Medals: 18



« Reply #26 - Posted 2012-01-09 18:45:19 »

OT: To solve the crash I ended up creating an undecorated LWJGL window that was (width+2, height) to prevent automatic fullscreen just for Intel cards. Guess why I hate Intel?

Java2D used to implement FSEM on Linux via a window whose viewport was the size of the desktop, though I believe as of Java 6 they have "true" full screen functionality implemented.  I'm not sure if they did so because of time constraints, buggy native support, nobody cared about games on Linux, or what.
Offline javaKnight

Junior Newbie





« Reply #27 - Posted 2012-01-10 01:31:24 »

Today I tried to change the options of virtual machine to force acceleration on graphics card. After a while that give me an answer - support for DirectX/OpenGL is default enabled. When I turned off Direct3D acceleration, render time gone higher, so that solves my case Smiley Java2d is trying to use platform depended acceleration and if that fail, there is switch to software rendering. That's it - clean and simple Smiley
Offline theagentd
« Reply #28 - Posted 2012-01-10 05:19:30 »

Today I tried to change the options of virtual machine to force acceleration on graphics card. After a while that give me an answer - support for DirectX/OpenGL is default enabled. When I turned off Direct3D acceleration, render time gone higher, so that solves my case Smiley Java2d is trying to use platform depended acceleration and if that fail, there is switch to software rendering. That's it - clean and simple Smiley
For a really demanding game (one that runs at <10 FPS without hardware acceleration for example) this is way too unreliable though. It might work everywhere, but not be playable everywhere.

Myomyomyo.
Offline gimbal

JGO Knight


Medals: 25



« Reply #29 - Posted 2012-01-10 10:38:37 »

Today I tried to change the options of virtual machine to force acceleration on graphics card. After a while that give me an answer - support for DirectX/OpenGL is default enabled. When I turned off Direct3D acceleration, render time gone higher, so that solves my case Smiley Java2d is trying to use platform depended acceleration and if that fail, there is switch to software rendering. That's it - clean and simple Smiley

Hmm, are you drawing images with bit translucency I wonder? As far as I know those type of images cannot be accelerated under hardware rendering environments but will perform a whole lot better in a software rendering one (where they can be accelerated). You could try switching to full translucent images to see if that makes a difference with D3D/OGL enabled.

Note that I disabled hardware support by default myself; the type of games I make (simple retro remakes) generally don't need it. Gives the least amount of cross-computer misery.
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.

Pippogeek (39 views)
2014-09-24 16:13:29

Pippogeek (30 views)
2014-09-24 16:12:22

Pippogeek (20 views)
2014-09-24 16:12:06

Grunnt (46 views)
2014-09-23 14:38:19

radar3301 (28 views)
2014-09-21 23:33:17

BurntPizza (64 views)
2014-09-21 02:42:18

BurntPizza (36 views)
2014-09-21 01:30:30

moogie (42 views)
2014-09-21 00:26:15

UprightPath (51 views)
2014-09-20 20:14:06

BurntPizza (54 views)
2014-09-19 03:14:18
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

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

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

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

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

HotSpot Options
by dleskov
2014-07-08 01:59:08
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!