【问题标题】:Java copying buffered Image perfomance issueJava 复制 bufferedImage 性能问题
【发布时间】:2011-12-19 02:47:00
【问题描述】:

他!

我正在写一个游戏。因为随着时间的推移没有太大的变化,我转而缓冲棋盘的某些部分(在其上进行游戏)并不时复制它。我在前台更改了内容,所以我仍然需要高 fps。我还想放大,这就是有趣的开始:为了节省内存,我重用了缓冲区。每当我缩放应用程序滞后,然后正常运行。

分析后,我发现了两个性能杀手:

  • 清除后台缓冲区(4000x4000 像素,大约需要 29 毫秒。为了保持透明度,我使用 g.fillRect)

  • 将缓冲区复制回真实图像(这当然不是实时的,但同样来自 getBufferStrategy())。这需要 300 毫秒,下一次大约 150 毫秒,然后从第三帧开始它运行顺利。

澄清问题可能出在一些代码上。我通过以下方式创建自己的缓冲区:

GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice device = env.getDefaultScreenDevice();
GraphicsConfiguration config = device.getDefaultConfiguration();
image = config.createCompatibleImage(width, height,Transparency.TRANSLUCENT);

现在是我将缓冲区复制回图像的部分。请注意,我需要切掉缓冲区的某些部分,这就是我选择最大参数调用的原因。

g.drawImage(image, vs.boardOffsetX, vs.boardOffsetY, targetWidth, targetHeight, 0, 0, sourceWidth, sourceHeight, null);

最后,对于我的另一个问题:我清除图像如下:

Graphics2D g = (Graphics2D) image.getGraphics();
Color transparent = new Color(0, 0, 0, 0);
g.setColor(transparent);
g.setComposite(AlphaComposite.Src);
g.fillRect(0, 0, image.getWidth(null), image.getHeight(null));

非常感谢!被困了很长一段时间。不要害羞就我的方法给我风格建议:这是我第一次诚实地尝试图形。

谢谢!

edit:我真正不明白的部分是完全相同的操作需要非常不同的时间。除了我的线程之外,只有 AWT-Thread 运行,我得到两次〜300ms,然后下降到像 10µs !!!!这对于复制 1600 万像素来说非常快。 有人了解这种效果吗?并且可能知道“预优化”这种行为的方法?

【问题讨论】:

  • 我看到的第一个危险信号是你有一个 4000x4000 像素的后台缓冲区。为什么需要这么大的?
  • 另外,您是否需要使用image 的宽度和高度清除您的g 实例?这将是一个 4000x4000 的矩形来填充,透明度不低于。似乎没有必要,只需清除当时屏幕上的任何矩形即可。此外,将 alpha 设置为 0,您将获得完全不透明的颜色。也许放弃透明度。
  • 我需要缓冲区,因为在最大缩放中,需要显示的板就是那么大。我同意,它肯定会很慢,但是在每一帧或至少每次滚动时重新渲染完整的内容会更慢。所以是的,我需要它。只删除部分听起来不错,但很复杂……稍后会研究。不过谢谢!

标签: java performance awt


【解决方案1】:

听说我无法真正解决问题,您可能会感兴趣。相反,我取消了最后一个缩放步骤,将最大缓冲区的大小限制为 2000x2000,并消除了问题中最糟糕的部分。缩放现在非常顺利(我测量了第一次 drawImage 调用的 80 毫秒。这仍然很多,但由于视图变化很快,你并没有真正注意到它)。

在我的研究中,我还发现我无法明确强制 java 创建所需大小的加速 VolatileImages。这可能是问题所在——天知道为什么。不过我还是想知道...

但是给有同样问题的人最后一句话:环游。

感谢您的帮助!

【讨论】:

    【解决方案2】:

    不知道它是否对您有帮助,但使用System.arraycopy() 复制我的应用程序会稍微快一些。

    BufferedImage tmp = (BufferedImage) img;
    int[] src = ((DataBufferInt) tmp.getRaster().getDataBuffer()).getData();
    int[] dst = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData();
    System.arraycopy(src, 0, dst, 0, dst.length);
    

    【讨论】:

    • 不错的主意。 arraycopy 通常对这些东西有最好的性能。但我不确定提问者是否需要复制他的图像。他需要将其绘制到图形上下文中。也许有一些方法可以复制到像素缓冲区?
    • 这个主意不错。不能比那更快(除了实际使用图形卡)。但是:我试图绘制一个策略缓冲区,这意味着我几乎只有 Graphics2D-Object。所以没有光栅......有没有办法明确告诉java我不想调整大小?因为我的图像复制确实应该逐像素进行。
    猜你喜欢
    • 1970-01-01
    • 2015-07-22
    • 1970-01-01
    • 2018-09-24
    • 1970-01-01
    • 2011-12-06
    • 2014-08-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多