Java2D Performance Issues

I have performance features with Java2D. I know the sun.java2d.opengl VM parameter to enable 3D acceleration for 2D, but even using this there are some strange problems.

Below are the results of the tests:

Drawing a 25x18 map with 32x32 pixel tiles on JComponent
Image 1 = .bmp format, Image 2 = .png format

Without -Dsun.java2d.opengl = true

120 FPS using .BMP image 1
13 FPS using .PNG 2 image

C -Dsun.java2d.opengl = true

12 FPS using .BMP image 1
700 FPS using .PNG 2 image

Without acceleration, I assume that some kind of conversion happens with every drawImage () that I do in the software, and significantly reduces FPS in the case of .PNG. Why, though, with acceleration, the results will switch (and PNG actually performs incredibly faster) ?! Madness!

.BMP Image 1 is converted to the image type TYPE_INT_RGB..PNG Image 2 is converted to the image type TYPE_CUSTOM. To get a constant speed with and without opengl acceleration, I need to create a new BufferedImage with the image type TYPE_INT_ARGB and draw image 1 or image 2 on this new image.

Here are the results performed with this:

Without -Dsun.java2d.opengl = true

120 FPS using .BMP image 1
120 FPS using .PNG 2 image

C -Dsun.java2d.opengl = true

700 FPS using .BMP image 1
700 FPS using .PNG 2 image

My real question is: can I assume that TYPE_INT_ARGB will be the native image type for all systems and platforms? I assume that this value may be different. Is there any way for me to get my own value so that I can always create new BufferedImages for maximum performance?

Thanks in advance...

+49
java java-2d
Oct 13 '08 at 6:57
source share
3 answers

I think I found a solution by researching and putting together too many queries on Google.

Here it is, comments and all:

private BufferedImage toCompatibleImage(BufferedImage image) { // obtain the current system graphical settings GraphicsConfiguration gfxConfig = GraphicsEnvironment. getLocalGraphicsEnvironment().getDefaultScreenDevice(). getDefaultConfiguration(); /* * if image is already compatible and optimized for current system * settings, simply return it */ if (image.getColorModel().equals(gfxConfig.getColorModel())) return image; // image is not optimized, so create a new image that is BufferedImage newImage = gfxConfig.createCompatibleImage( image.getWidth(), image.getHeight(), image.getTransparency()); // get the graphics context of the new image to draw the old image on Graphics2D g2d = newImage.createGraphics(); // actually draw the image and dispose of context no longer needed g2d.drawImage(image, 0, 0, null); g2d.dispose(); // return the new optimized image return newImage; } 

In my previous post, GraphicsConfiguration contained the information needed to create optimized images in the system. This seems to work pretty well, but I would have thought that Java would automatically do it for you. Obviously, you cannot feel too comfortable with Java. :) I guess I answered my question. Well, hopefully this helps some of you I've seen trying to use Java for 2D games.

+58
Oct 13 '08 at 9:04
source share

From what I remember when I thought about graphical programming in Java, the built-in libraries are slow. I was told on GameDev.Net that anyone doing something serious would have to use something like jogl

+1
Oct 13 '08 at 7:01
source share

Ok, this is an old post, but I would like to share my conclusions about direct drawing using Swing / AWT without BufferedImage.

Some kind of drawing, like 3D, is best done when you draw directly in the int [] buffer. After creating the images, you can use an instance of ImageProducer , such as MemoryImageSource , to create the images. I assume that you know how to execute your drawings directly, without using Graphics / Graphics2.

  /** * How to use MemoryImageSource to render images on JPanel * Example by A.Borges (2015) */ public class MyCanvas extends JPanel implements Runnable { public int pixel[]; public int width; public int height; private Image imageBuffer; private MemoryImageSource mImageProducer; private ColorModel cm; private Thread thread; public MyCanvas() { super(true); thread = new Thread(this, "MyCanvas Thread"); } /** * Call it after been visible and after resizes. */ public void init(){ cm = getCompatibleColorModel(); width = getWidth(); height = getHeight(); int screenSize = width * height; if(pixel == null || pixel.length < screenSize){ pixel = new int[screenSize]; } mImageProducer = new MemoryImageSource(width, height, cm, pixel,0, width); mImageProducer.setAnimated(true); mImageProducer.setFullBufferUpdates(true); imageBuffer = Toolkit.getDefaultToolkit().createImage(mImageProducer); if(thread.isInterrupted() || !thread.isAlive()){ thread.start(); } } /** * Do your draws in here !! * pixel is your canvas! */ public /* abstract */ void render(){ // rubisch draw int[] p = pixel; // this avoid crash when resizing if(p.length != width * height) return; for(int x=0; x < width; x++){ for(int y=0; y<height; y++){ int color = (((x + i) % 255) & 0xFF) << 16; //red color |= (((y + j) % 255) & 0xFF) << 8; //green color |= (((y/2 + x/2 - j) % 255) & 0xFF) ; //blue p[ x + y * width] = color; } } i += 1; j += 1; } private int i=1,j=256; @Override public void run() { while (true) { // request a JPanel re-drawing repaint(); try {Thread.sleep(5);} catch (InterruptedException e) {} } } @Override public void paintComponent(Graphics g) { super.paintComponent(g); // perform draws on pixels render(); // ask ImageProducer to update image mImageProducer.newPixels(); // draw it on panel g.drawImage(this.imageBuffer, 0, 0, this); } /** * Overrides ImageObserver.imageUpdate. * Always return true, assuming that imageBuffer is ready to go when called */ @Override public boolean imageUpdate(Image image, int a, int b, int c, int d, int e) { return true; } }// end class 

Please note that we need a unique instance of MemoryImageSource and Image . Do not create a new image or a new ImageProducer for each frame unless you have resized your JPanel. See the init () method above.

In the rendering stream, set repaint () . In Swing, repaint () will call an overridden paintComponent () , where it will call the render () method, and then ask to update the imageProducer image. Using Image done, draw it using Graphics.drawImage () .

To create a compatible image, use ColorModel when creating the image . I am using GraphicsConfiguration.getColorModel () :

 /** * Get Best Color model available for current screen. * @return color model */ protected static ColorModel getCompatibleColorModel(){ GraphicsConfiguration gfx_config = GraphicsEnvironment. getLocalGraphicsEnvironment().getDefaultScreenDevice(). getDefaultConfiguration(); return gfx_config.getColorModel(); } 
-one
Feb 10 '16 at 4:17
source share



All Articles