Java 硬件加速

Posted

技术标签:

【中文标题】Java 硬件加速【英文标题】:Java Hardware Acceleration 【发布时间】:2011-06-05 08:49:00 【问题描述】:

我一直在研究 Java 的硬件加速功能,但我仍然有点困惑,因为我在网上找到的网站都没有直接明确回答我的一些问题。下面是我对 的疑问:

1) 在 Eclipse 版本 3.6.0 中,带有 Mac OS X 的最新 Java 更新(我认为是 1.6u10),是否默认启用硬件加速?我在某处读到

someCanvas.getGraphicsConfiguration().getBufferCapabilities().isPageFlipping()

应该指示是否启用了硬件加速,并且我的程序在我的主 Canvas 实例上运行以进行绘图时报告返回 true。如果我的硬件加速现在没有启用,或者默认情况下没有启用,我需要做什么来启用它?

2)我在这里和那里看到了几篇关于 BufferedImage 和 VolatileImage 之间区别的文章,主要是说 VolatileImage 是硬件加速图像,存储在 VRAM 中以进行快速复制操作。但是,我还发现了一些 BufferedImage 也被称为硬件加速的实例。 BufferedImage 硬件是否也在我的环境中加速?如果两种类型都是硬件加速的,那么使用 VolatileImage 有什么好处?我对在两者都有加速的情况下拥有 VolatileImage 的优势的主要假设是 VolatileImage 能够检测到它的 VRAM 何时被转储。但是如果 BufferedImage 现在也支持加速,那它是不是也内置了同样的检测功能,只是对用户隐藏,以防内存被转储?

3) 使用有什么好处

someGraphicsConfiguration.getCompatibleImage/getCompatibleVolatileImage()

相对

ImageIO.read()

在一个教程中,我一直在阅读有关正确设置渲染窗口的一些一般概念 (tutorial),它使用 getCompatibleImage 方法(我相信该方法返回一个 BufferedImage)来获取他们的“硬件加速”图像以进行快速绘图,这与问题 2 是否是硬件加速有关。

4) 这不是硬件加速,但我一直很好奇:我是否需要订购要绘制的图形?我知道,当通过 C/C++ 使用 OpenGL 时,最好确保在需要一次绘制的所有位置都绘制相同的图形,以减少当前纹理需要切换的次数。从我读到的内容来看,Java 似乎会为我解决这个问题,并确保以最优化的方式绘制内容,但同样,从来没有人这么清楚地表达过。

5) 哪些 AWT/Swing 类支持硬件加速,应该使用哪些?我目前正在使用一个扩展 JFrame 的类来创建一个窗口,并向它添加一个 Canvas,我从中创建一个 BufferStrategy。这是一种好的做法,还是有其他我应该实施的方法?

非常感谢您抽出宝贵时间,我希望我提供了明确的问题和足够的信息,以便您回答我的几个问题。

【问题讨论】:

【参考方案1】:

从一些older documentation 来看,您可以通过检查sun.java2d.opengl 属性来判断Sun JVM 是否启用了硬件加速。

很遗憾,我不知道这是否适用于 Apple JVM。

您可以使用ImagegetCapabilities(GraphicsConfiguration).isAccelerated() 检查单个图像是否经过硬件加速

说了这么多,我看到的所有文档(包括this one)都暗示BufferedImage不是硬件加速的。出于这个原因,Swing 也已更改为使用 VolatileImages 进行双缓冲。

【讨论】:

在哪里可以找到 sun.java2d.opengl 属性?我见过提到它,但我不知道在哪里检查或放置它以确保它在 Mac/Eclipse 上启用。另外:download.oracle.com/javase/1.5.0/docs/guide/2d/… 表示 BufferedImages 在 1.5.0 中进行管理并缓存在视频内存中。 让我们看看...我认为是System.getProperty("sun.java2d.opengl") 来获取财产的价值。至于BufferedImage,它说它可以缓存在视频内存中,但除此之外没有说明实际操作它。 打印 getProperty 的输出会给我“null”到控制台。根据我对 Java 中加速工作原理的了解,BufferedImage 是否可以在视频内存中实现 VolatileImage 应该具有的快速复制?如果它使用视频到视频的复制,我会假设会是这种情况。 我对 Java 中的硬件加速也不太了解(我是一个网络人),我只是假设 VolatileImage 成为 OpenGL 有一些好处(在 DirectDraw/Direct2D 上Windows) 加速。 可能有,这就是我问所有这些问题的原因,呵呵。我很感激帮助。希望 Java 大师会注意到这些问题并在某个时候回答它:)【参考方案2】:

1) 到目前为止,默认情况下从未启用硬件加速,据我所知,它还没有改变。要激活渲染加速,请在程序启动时将此参数 (-Dsun.java2d.opengl=true) 传递给 Java 启动器,或在使用任何渲染库之前设置它。 System.setProperty("sun.java2d.opengl", "true");是可选参数。

2) 是的,BufferedImage 封装了一些管理易失性内存的细节,因为当BufferdImage 被加速时,它的副本会以VolatileImage 的形式存储在 V-Ram 中。

BufferedImage 的好处是只要你不弄乱它包含的像素,只需像调用graphics.drawImage() 一样复制它们,那么BufferedImage 将在某个非指定数量后加速副本,它将为您管理VolatileImage

BufferedImage 的缺点是,如果您正在进行图像编辑,更改BufferedImage 中的像素,在某些情况下它会放弃尝试加速它,此时如果您正在寻找高性能渲染您的编辑需要考虑管理您自己的VolatileImage。不知道是哪些操作让BufferedImage放弃了为你加速渲染的尝试。

3) 使用createCompatibleImage()/createCompatibleVolatileImage()的优势 是ImageIO.read() 不会对默认支持的图像数据模型进行任何转换。 因此,如果您导入 PNG,它将以 PNG 阅读器构建的格式表示。这意味着每次由GraphicsDevice 渲染时,都必须先将其转换为兼容的图像数据模型。

BufferedImage image = ImageIO.read ( url );
BufferedImage convertedImage = null;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment ();
GraphicsDevice gd = ge.getDefaultScreenDevice ();
GraphicsConfiguration gc = gd.getDefaultConfiguration ();
convertedImage = gc.createCompatibleImage (image.getWidth (), 
                                           image.getHeight (), 
                                           image.getTransparency () );
Graphics2D g2d = convertedImage.createGraphics ();
g2d.drawImage ( image, 0, 0, image.getWidth (), image.getHeight (), null );
g2d.dispose()

上述过程会将使用图像 io api 读取的图像转换为具有与默认屏幕设备兼容的图像数据模型的 BufferedImage,因此在渲染时无需进行转换。最有利的时候是您将非常频繁地渲染图像。

4) 您不需要努力批量渲染图像,因为大多数情况下 Java 会尝试为您执行此操作。您没有理由不尝试这样做,但通常最好先分析您的应用程序并确认图像渲染代码存在瓶颈,然后再尝试执行诸如此类的性能优化。主要缺点是它在每个 JVM 中的实现略有不同,然后增强可能毫无价值。

5) 据我所知,您所概述的设计是手动执行双缓冲和主动渲染应用程序时更好的策略之一。 http://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferStrategy.html 在此链接中,您将找到BufferStrategy 的描述。在描述中,它显示了一个代码 sn-p,这是使用BufferStrategy 对象进行主动渲染的推荐方法。我将这种特殊技术用于我的活动渲染代码。唯一的主要区别是在我的代码中。和你一样,我已经在 Canvas 的实例上创建了 BufferStrategy,我把它放在了 JFrame 上。

【讨论】:

大多数/所有示例都使用 JFrame 来存储 Canvas 是否有任何特殊原因?据我了解,Swing 非常糟糕。为什么不使用框架?我有可以做到这一点的代码,而且创建它似乎并不比创建 JFrame 更难。另外,如果默认情况下不启用硬件加速,如何启用? @FreezerBurn 我不知道为什么大多数示例都使用 JFrame 与 Frame。我想它是用 JFrame 完成的,因为这是最常见的。这只是推测,但我猜想在 Java 中手动渲染仅使用***容器(JFrame、Frame 等)和 Canvas,您选择哪一个几乎没有区别。要激活渲染加速,请在程序启动时将此 arg (-Dsun.java2d.opengl=true) 传递给 Java 启动器,或者在使用任何渲染库之前设置它。 (System.setProperty("sun.java2d.opengl", "true");) 可选参数。 JFrame 是 Swing,而 Frame/Canvas 是 AWT。 Swing 是较新的组件库,而 AWT 是旧的已弃用库。 Swing 使用轻量级组件,而 AWT 是本机组件。 JFrame 优于旧 AWT 组件。

以上是关于Java 硬件加速的主要内容,如果未能解决你的问题,请参考以下文章

观看视频时启用硬件加速有什么用?如果关闭硬件加速又有什么区别呢?

Android硬件加速介绍与实现

硬件加速

webview硬件加速应该开着还是关闭?webview是啥意思?

Android硬件加速

Android硬件加速