Java 2D Drawing Optimal Performance
Asked Answered
I

9

33

I'm in the process of writing a Java 2D game. I'm using the built-in Java 2D drawing libraries, drawing on a Graphics2D I acquire from a BufferStrategy from a Canvas in a JFrame (which is sometimes full-screened). The BufferStrategy is double-buffered. Repainting is done actively, via a timer. I'm having some performance issues though, especially on Linux.

And Java2D has so very many ways of creating graphics buffers and drawing graphics that I just don't know if I'm doing the right thing. I've been experimenting with graphics2d.getDeviceConfiguration().createCompatibleVolatileImage, which looks promising, but I have no real proof it it's going to be any faster if I switch the drawing code to that.

In your experience, what is the fastest way to render 2D graphics onto the screen in Java 1.5+? Note that the game is quite far ahead, so I don't want to switch to a completely different method of drawing, like OpenGL or a game engine. I basically want to know how to get the fastest way of using a Graphics2D object to draw stuff to the screen.

Intoxication answered 29/9, 2008 at 12:32 Comment(3)
Just out of curiosity, what is the game about? :DNightwalker
Re: Mario Ortegon: metalbeetle.com/spaceexploration . I didn't put a link into the main since that would just be stealth advertising.Intoxication
link looks a bit strange (..but that was 8 years ago)Kurbash
F
17

I'm having the same issues as you are I think. Check out my post here:

Java2D Performance Issues

It shows the reason for the performance degradation and how to fix it. It's not guaranteed to work well on all platforms though. You'll see why in the post.

Fourlegged answered 13/10, 2008 at 7:23 Comment(0)
I
35

A synthesis of the answers to this post, the answers to Consty's, and my own research:

What works:

  • Use GraphicsConfiguration.createCompatibleImage to create images compatible with what you're drawing on. This is absolutely essential!
  • Use double-buffered drawing via Canvas.createBufferStrategy.
  • Use -Dsun.java2d.opengl=True where available to speed up drawing.
  • Avoid using transforms for scaling. Instead, cache scaled versions of the images you are going to use.
  • Avoid translucent images! Bitmasked images are fine, but translucency is very expensive in Java2D.

In my tests, using these methods, I got a speed increase of 10x - 15x, making proper Java 2D graphics a possibility.

Intoxication answered 14/10, 2008 at 9:23 Comment(1)
In my case, the opengl flag brought my cpu usage down to 13% from 25%...Oysterman
F
17

I'm having the same issues as you are I think. Check out my post here:

Java2D Performance Issues

It shows the reason for the performance degradation and how to fix it. It's not guaranteed to work well on all platforms though. You'll see why in the post.

Fourlegged answered 13/10, 2008 at 7:23 Comment(0)
N
12

Here are some tips off the top of my head. If you were more specific and what you were trying to do I may be able to help more. Sounds like a game, but I don't want to assume.

Only draw what you need to! Don't blindly call repaint() all of the time, try some of the siblings like repaint(Rect) or repaint(x,y,w,h).

Be very careful with alpha blending as it can be an expensive operation to blending images / primitives.

Try to prerender / cache as much as possible. If you find yourself drawing a circle the same way, over and over, consider drawing in into a BufferedImage and then just draw the BufferedImage. You're sacrificing memory for speed (typical of games / high perf graphics)

Consider using OpenGL, use JOGL of LWJGL. JOGL is more Java-like whereas LWJGL provides more gaming functionality on top of OpenGL access. OpenGL can draw orders of magnitude (with proper hardware and drivers) than Swing can.

Nerissa answered 1/10, 2008 at 11:50 Comment(0)
T
3

There's an important one which hasn't been mentioned yet, I think: cache images of everything you can. If you have an object that is moving across the screen, and it's appearance doesn't change much, draw it to an image and then render the image to the screen in a new position each frame. Do that even if the object is a very simple one - you might be surprised at how much time you save. Rendering a bitmap is much faster than rendering primitives.

You might also want to look at setting rendering hints explicitly, and turning off things like antialiasing if quality considerations permit.

Televise answered 1/5, 2009 at 19:11 Comment(0)
L
1

I've done some basic drawing applications using Java. I haven't worked on anything too graphic-intensive, but I would recommend that you have a good handle on all the 'repaint' invocations. An extra repaint call on a parent container could double the amount of rendering your doing.

Levitical answered 29/9, 2008 at 12:50 Comment(0)
L
1

I've been watching this question, hoping someone would offer you a better answer than mine.

In the meantime, I found the following Sun white paper which was written after a beta release of jdk 1.4. There are some interesting recommendations here on fine-tuning, including the runtime flags (at the bottom of the article):

"Runtime Flag For Solaris and Linux

Starting with the Beta 3 release of the SDK, version 1.4, Java 2D stores images in pixmaps by default when DGA is not available, whether you are working in a local or remote display environment. You can override this behavior with the pmoffscreen flag:

-Dsun.java2d.pmoffscreen=true/false

If you set this flag to true, offscreen pixmap support is enabled even if DGA is available. If you set this flag to false, offscreen pixmap support is disabled. Disabling offscreen pixmap support can solve some rendering problems. "

Levitical answered 30/9, 2008 at 14:28 Comment(0)
T
0

make sure you use double buffering, draw first to one big buffer in memory that you then flush to screen when all drawing is done.

Thurlow answered 29/9, 2008 at 12:37 Comment(1)
Currently, I use myCanvas.createBufferStrategy(2). But I don't know if manually creating a Volatile buffer wouldn't be faster.Intoxication
W
0

There are couple of things you will need to keep in mind

1) is refreshing this link shows how to use swingtimers which might be a good option for calling repaint. Getting repaint figured out (as the previous posters have said is important so you're not doing too much work).

2) Make sure you're only doing drawing in one thread. Updating UI from mulitple threads can lead to nasty things.

3) Double Buffering. This makes the rendering smoother. this site has some more good info for you

Whisky answered 29/9, 2008 at 13:17 Comment(1)
link link It's better to avoid swing timers and rely on threads for anmation. It's also good practice to use active rendering instead of passing rendering relying on repaint()Sectary
E
0

An alternative if you don't want to go pure Java 2D is to use a game library such as GTGE or JGame (search for them on Google), then offer easy access to graphics and also offer double buffering and much simpler drawing commands.

Eucharist answered 17/11, 2008 at 5:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.