Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm trying to draw a bunch of translucent circles on a Swing JComponent. This isn't exactly fast, and I was wondering if there is a way to speed it up. My custom JComponent has the following paintComponent method:

public void paintComponent(Graphics g) {
    Rectangle view = g.getClipBounds();

    VolatileImage image = createVolatileImage(view.width, view.height);
    Graphics2D buffer = image.createGraphics();
    // translate to camera location
    buffer.translate(-cx, -cy);
    // renderables contains all currently visible objects
    for(Renderable r : renderables) {
        r.paint(buffer);
    }
    g.drawImage(image.getSnapshot(), view.x, view.y, this);
}

The paint method of my circles is as follows:

public void paint(Graphics2D graphics) {
    graphics.setPaint(paint);
    graphics.fillOval(x, y, radius, radius);
}

The paint is just an rgba color with a < 255:

Color(int r, int g, int b, int a)

It works fast enough for opaque objects, but is there a simple way to speed this up for translucent ones?

share|improve this question
    
Why are you rendering the circles through a volatile image instead of directly to the Graphics object of the paintComponent method? –  msell Nov 2 '13 at 18:24
    
@msell I would like to add a BufferedImageOp in the g.drawImage() method later on. According to this document, a VolatileImage should be fast (although I must admit I don't fully understand it). If there's another way to filter, I would be happy to try it. –  mdriesen Nov 2 '13 at 20:14
    
I see two possible performance issues in the given code. 1) You are recreating the volatile image in every paintComponent and 2) You could draw the image directly instead of using image.getSnaposhot(). See the example in the beginning of VolatileImage documentation for how to deal with both of the problems. –  msell Nov 3 '13 at 5:59
    
@msell Not recreating the image actually gave a noticeable speed boost. Thanks! I can't use your second suggestion though, as I need the following method for my filter: Graphics2D.drawImage(BufferedImage img, BufferedImageOp op, int x, int y), which doesn't work with VolatileImages. –  mdriesen Nov 3 '13 at 10:03
    
Instead of using VolatileImage, you could try using createCompatibleImage, which returns a BufferedImage that might be accelerated. On the other hand the BufferedImageOp could be really slow and make other optimizations useless. What do you plan to do with the BufferedImageOp? What do you want to achieve with all of this rendering? –  msell Nov 3 '13 at 10:49

2 Answers 2

up vote 0 down vote accepted

The immediate potential performance problems I see in your code are:

  1. You are recreating the volatile image in every paintComponent
  2. Calling image.getSnapshot() to convert the VolatileImage to BufferedImage.

There is a good example in the beginning of VolatileImage documentation on how to deal with both of the problems.

In the comments you say that 2. is required so that you can later use BufferedImageOp to filter the rendered image. I think this is a mistake, because as far as I know, BufferedImageOp processes each individual pixel of the image on CPU. This operation alone is likely much slower than any problems regarding image creation or conversion.

I recommend you to take a look at AlphaComposite and the related tutorial. Alternatively depending on what exactly you want to achieve, you could just fill another semi-transparent rectangle on top of everything. With a TexturePaint you can probably create the noise filter you are looking for.

In addition instead of using VolatileImages, you could try GraphicsConfiguration.createCompatibleImage to create accelerated BufferedImages. Benchmark if this has the same performance as VolatileImage. If it does, it will be easier to manage than VolatileImage.

share|improve this answer
    
Accepting this as the answer, as the tips gave a noticeable speed boost. –  mdriesen Nov 15 '13 at 20:17

Pixel-pushing speeds are a known limitation of Java's out-of-box software renderer. Even with GPU hardware rendering, built for pushing pixels, overdraw / pixel blending / fill rates are known to have profound impacts on performance. Nevertheless, this is one of the reasons we have GPUs. If it's mission critical, I suggest a low-level library that provides access to native GPU functions, like LWJGL or JOGL, or else google "fast 2D graphics libraries Java".

P.S. Under the hood, millions of division and conditional operations have to take place every tick, in software, in order to support what you're trying to do, and all on a single thread / core (the main thread). GPUs handle this load through being massively parallel -- several tens to several hundreds of cores will be operating on large blocks of pixels simultaneously, reducing blending costs by orders of magnitude.

Slick2D may be a good option for you, as it is a 2D library that utilises LWJGL / OpenGL / your GPU under the hood.

share|improve this answer
    
Could painting a translucent texture possibly be any less resource-intensive than what the question asker is doing now? –  Micah - ps I love you Nov 2 '13 at 14:56
1  
The only things which affect the performance, aside from system CPU, are (1) the number of discrete entities to be blended onto the background surface, (2) the size of those entities, and (3) the complexity of the logical and arithmetic operations applied as per the blend mode, to each individual pixel. In software, I can guarantee you the performance will differ by environment. In hardware, given that you are only performing 2D ops, performance isn't even going to be a concern. So from the point of view of mitigating risk on less powerful systems, GPU or a custom-built 2D library is best. –  Arcane Engineer Nov 2 '13 at 15:03
    
"GPU or a custom-built 2D library is best." Could you clarify? Something like using shaders? –  Micah - ps I love you Nov 2 '13 at 15:12
    
@nick I had a look at LWJGL a while ago, and it seems very interesting. But I would first like to try plain java2d before going that way. –  mdriesen Nov 2 '13 at 20:19
    
You'll find even fairly professional software-rendering libraries like PulpCore are going to have problems with fill rates. Slick2D wraps LWJGL, so this may be a viable option for you. See edit. –  Arcane Engineer Nov 3 '13 at 21:52

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.