Java 2D 绘图优化性能
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/148478/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java 2D Drawing Optimal Performance
提问by Zarkonnen
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.
我正在编写 Java 2D 游戏。我正在使用内置的 Java 2D 绘图库,在我从 JFrame 中的 Canvas(有时是全屏的)的 BufferStrategy 中获取的 Graphics2D 上进行绘制。BufferStrategy 是双缓冲的。重绘是通过计时器主动完成的。不过,我遇到了一些性能问题,尤其是在 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.
Java2D 有很多创建图形缓冲区和绘制图形的方法,我只是不知道我是否在做正确的事情。我一直在试验 graphics2d.getDeviceConfiguration().createCompatibleVolatileImage,它看起来很有希望,但我没有真正的证据表明如果我将绘图代码切换到它会更快。
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.
根据您的经验,在 Java 1.5+ 中将 2D 图形渲染到屏幕上的最快方法是什么?请注意,游戏遥遥领先,因此我不想切换到完全不同的绘图方法,例如 OpenGL 或游戏引擎。我基本上想知道如何以最快的方式使用 Graphics2D 对象将内容绘制到屏幕上。
采纳答案by Consty
I'm having the same issues as you are I think. Check out my post here:
我遇到了和你想的一样的问题。在这里查看我的帖子:
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.
它显示了性能下降的原因以及如何修复它。但不能保证在所有平台上都能正常工作。你会在帖子中看到原因。
回答by Tom
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.
确保使用双缓冲,首先绘制到内存中的一个大缓冲区,然后在所有绘制完成后刷新到屏幕。
回答by Brendan Cashman
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.
我已经使用 Java 完成了一些基本的绘图应用程序。我没有做过任何图形密集型的工作,但我建议您对所有“重绘”调用有一个很好的处理。对父容器进行额外的重绘调用可能会使渲染量加倍。
回答by Steve g
There are couple of things you will need to keep in mind
有几件事你需要记住
1) is refreshing this linkshows 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).
1) 正在刷新此链接显示如何使用摆动计时器,这可能是调用重绘的不错选择。弄清楚重绘(正如之前的海报所说的那样很重要,所以你不会做太多的工作)。
2) Make sure you're only doing drawing in one thread. Updating UI from mulitple threads can lead to nasty things.
2)确保您只在一个线程中进行绘图。从多线程更新 UI 可能会导致令人讨厌的事情。
3) Double Buffering. This makes the rendering smoother. this sitehas some more good info for you
3) 双缓冲。这使得渲染更流畅。 这个网站有一些更好的信息给你
回答by Brendan Cashman
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 paperwhich 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):
同时,我发现了以下Sun 白皮书,它是在 jdk 1.4 的 beta 版本发布之后编写的。这里有一些关于微调的有趣建议,包括运行时标志(在文章底部):
"Runtime Flag For Solaris and Linux
" Solaris 和 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:
从 SDK 的 Beta 3 版本 1.4 版开始,当 DGA 不可用时,Java 2D 默认将图像存储在像素图中,无论您是在本地还是远程显示环境中工作。您可以使用 pmoffscreen 标志覆盖此行为:
-Dsun.java2d.pmoffscreen=true/false
-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."
如果将此标志设置为 true,则即使 DGA 可用,也会启用屏幕外像素图支持。如果将此标志设置为 false,将禁用屏幕外像素图支持。禁用屏幕外像素图支持可以解决一些渲染问题。”
回答by basszero
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).
只画你需要的东西!不要一直盲目地调用repaint(),尝试一些兄弟姐妹,例如repaint(Rect) 或repaint(x,y,w,h)。
Be very careful with alpha blending as it can be an expensive operation to blending images / primitives.
使用 alpha 混合时要非常小心,因为它可能是混合图像/基元的昂贵操作。
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)
尝试尽可能多地预渲染/缓存。如果您发现自己以相同的方式一遍又一遍地绘制圆,请考虑绘制到 BufferedImage 中,然后仅绘制 BufferedImage。您正在为速度牺牲内存(典型的游戏/高性能图形)
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.
考虑使用OpenGL,使用LWJGL的JOGL。JOGL 更像 Java,而 LWJGL 在 OpenGL 访问之上提供更多游戏功能。OpenGL 可以比 Swing 绘制数量级(使用适当的硬件和驱动程序)。
回答by Zarkonnen
A synthesis of the answers to this post, the answers to Consty's, and my own research:
对这篇文章的回答、对Consty 的回答以及我自己的研究的综合:
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.
- 使用
GraphicsConfiguration.createCompatibleImage
来创建你画什么兼容的影像。这绝对是必不可少的! - 通过
Canvas.createBufferStrategy
. - 使用
-Dsun.java2d.opengl=True
其中可加快绘图。 - 避免使用变换进行缩放。相反,缓存您要使用的图像的缩放版本。
- 避免半透明图像!位掩码图像很好,但半透明在 Java2D 中非常昂贵。
In my tests, using these methods, I got a speed increase of 10x - 15x, making proper Java 2D graphics a possibility.
在我的测试中,使用这些方法,我的速度提高了 10 到 15 倍,使正确的 Java 2D 图形成为可能。
回答by Paul Sagor
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.
如果您不想使用纯 Java 2D,另一种选择是使用诸如 GTGE 或 JGame 之类的游戏库(在 Google 上搜索它们),然后提供对图形的轻松访问,并提供双缓冲和更简单的绘图命令。
回答by DJClayworth
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.
您可能还想查看明确设置渲染提示,并在质量考虑允许的情况下关闭抗锯齿等功能。