Java2D性能问题

我在Java2D上performance怪异。 我知道sun.java2d.opengl虚拟机参数为2D启用3D加速,但即使使用它也有一些奇怪的问题。

这是我跑的testing的结果:

在JComponent上绘制32×32像素图块的25×18地图
图片1 = .bmp格式,图片2 = A .png格式

没有-Dsun.java2d.opengl = true

120 FPS使用.BMP图像1
13 FPS使用.PNG图像2

用-Dsun.java2d.opengl = true

12 FPS使用.BMP图像1
700 FPS使用.PNG图像2

如果没有加速,我假设我正在用软件做的每一个drawImage()都会发生某种转换,而在.PNG的情况下,我们正在大幅降低FPS。 但是,为什么加速呢,结果会改变(而PNG实际上performance得更快)呢? 疯狂!

.BMP Image 1被转换为TYPE_INT_RGB的图像types。 .PNG图像2被转换为TYPE_CUSTOM的图像types。 为了在使用和不使用opengl加速的情况下获得一致的速度,我必须创build一个新的带有TYPE_INT_ARGB图像types的BufferedImage,并将Image 1或Image 2绘制到这个新图像上。

以下是运行结果:

没有-Dsun.java2d.opengl = true

120 FPS使用.BMP图像1
120 FPS使用.PNG图像2

用-Dsun.java2d.opengl = true

700 FPS使用.BMP图像1
700 FPS使用.PNG图像2

我真正的问题是,我可以假设TYPE_INT_ARGB将是所有系统和平台的本机图像types? 我假设这个值可能不同。 有什么方法可以让我获得本机值,以便始终可以创build新的BufferedImages以获得最佳性能?

提前致谢…

我想我通过研究和search太多谷歌searchfind了一个解决scheme。

这里是,评论和所有:

private BufferedImage toCompatibleImage(BufferedImage image) { // obtain the current system graphical settings GraphicsConfiguration gfx_config = GraphicsEnvironment. getLocalGraphicsEnvironment().getDefaultScreenDevice(). getDefaultConfiguration(); /* * if image is already compatible and optimized for current system * settings, simply return it */ if (image.getColorModel().equals(gfx_config.getColorModel())) return image; // image is not optimized, so create a new image that is BufferedImage new_image = gfx_config.createCompatibleImage( image.getWidth(), image.getHeight(), image.getTransparency()); // get the graphics context of the new image to draw the old image on Graphics2D g2d = (Graphics2D) new_image.getGraphics(); // 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 new_image; } 

在我之前的文章中,GraphicsConfiguration是在系统上创build优化图像所需的信息。 它似乎工作得很好,但我会认为Java会自动为你做这个。 显然,你不能太习惯于Java。 :)我想我最终回答了我自己的问题。 噢,好吧,希望这会对你们中的一些人有所帮助。

从我记得当时我正在考虑使用Java进行graphics编程时,内置库很慢。 我在GameDev.Net上被告知,任何认真做事的人都必须使用像jogl这样的东西

那么,这是旧的post,但我想分享我的发现与Swing / AWT直接绘图,没有BufferedImage。

某些types的绘图(如3D)在直接绘制到int []缓冲区时更好。 完成图像后,您可以使用ImageProducer实例(如MemoryImageSource )来生成图像。 我假设你知道如何直接执行你的绘图,没有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 

请注意,我们需要MemoryImageSourceImage的唯一实例。 除非您调整了JPanel的大小,否则不要为每个帧创build新的Image或新的ImageProducer。 见上面的init()方法。

在渲染线程中,请求重绘() 。 在Swing上, repaint()会调用被覆盖的paintComponent() ,在那里调用render()方法,然后让你的imageProducer更新图像。 完成图像后,用Graphics.drawImage()绘制。

要有兼容的图像,请在创build图像时使用适当的ColorModel 。 我使用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(); }