快速Java2D硬件缩放图像

时间:2014-10-23 17:59:55

标签: java

我正在尝试使用Java2D在运行时使用某种类似的抗锯齿插值(例如双线性)来扩展后备缓冲区。我的想法是将场景渲染到此图像,然后在全屏模式下放大图像以匹配用户的任何分辨率。

请注意,全屏模式很重要。在窗口模式下不会发生这种情况。

使用硬件扩展有一种快速的方法吗? Javadocs表明它存在(-Dsun.java2d.ddscale = true)但它对我没有影响。

以下是代码:

// Initialization in AWT Canvas
buffer_ = createImage(1280, 800);

// Several hundred large draw calls into the buffer that renders the entire scene - executes fast (~10ms)
drawScene(buffer_.getGraphics());

// Upscaling buffer to screen. If I don't upscale it executes very fast (<1ms)
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(buffer_, 0, 0, 1920, 1200, null);

结果:

  • 最近邻(约2ms)
  • 双线性(约40ms)
  • Bicubic(约140ms)

图像是一个TYPE_INT_RGB不透明的BufferedImage,我正在绘制一个AWT画布。

我尝试过的其他事情:

  • VolatileImage(无性能变化)
  • Dsun.java2d.ddscale = true(无变化)
  • Dsun.java2d.opengl = true(所有命令慢约3倍)
  • AffineTransform(无变化)
  • createBufferStrategy和通过调用Graphics2D.scale“预缩放”(慢得多,缩放每个绘制调用而不是1个大缓冲区)。请注意,无需缩放的BufferStrategy无论如何都不会提高速度。
  • JPanel而非Canvas(约慢1.5倍)
  • imgScalr“library”(这只是跟我上面的g.drawImage完全一样)

其他一些有用的说明:

  • buffer_.getCapabilities(gc).isAccelerated()返回false(在窗口模式下为true
  • 这是遗留代码,我有更新的代码,所有GL都可以非常快速地进行扩展,但不希望重写遗留程序。建议我的硬件实际上支持图像的硬件缩放。
  • AMD HD5770显卡
  • Windows 7最新的Java 8作为JVM运行。

感谢您的帮助。在这一点上,我很遗憾地考虑将所有内容转换为GL只是为了这一件事......但必须有答案!

2 个答案:

答案 0 :(得分:0)

虽然我认为你的方法在技术上是可行的,但我想知道你为什么要这样设置固定分辨率的渲染。

从图形质量的角度来看,应该立即将事物渲染到目标分辨率,完全消除缩放。我意识到位图图形(如瓷砖等)需要在某个时刻进行缩放,只是我不明白为什么需要在关键路径上进行(实时)。我对此的首选方法是将位图预先缩放到所需的分辨率一次(然后将它们缓存在内存中甚至在磁盘上缓存,具体取决于哪种更新)。

您可能需要检查一些内容,确保内部使用的图像类型与渲染表面兼容(而不是使用硬编码的TYPE_INT_RGB,使用createCompatibleImage的变体创建后台缓冲区,以确保不需要格式转换)。此外,还有一大堆选项可以改变Graphics2D在幕后使用的内容:http://docs.oracle.com/javase/7/docs/technotes/guides/2d/flags.html

最后,您可能想要检查您是否正在使用缓冲图像执行任何“禁止”操作,例如直接访问底层缓冲区数组(Can't accelerate pixel-modified BufferedImages),这会干扰javas的能力使用硬件加速。

答案 1 :(得分:0)

我还没有在上述情况下使用全屏独占模式,但我确实有一个解决方法。

保持窗口模式,将窗口大小设置为与屏幕大小相匹配,将其位置设置为graphicsDevice.getDefaultConfiguration().getBounds(),然后设置为setUndecorated(true)。最后,使用java.awt.Robot将鼠标指针限制在窗口中。

不理想,但在视觉上它与全屏无法区分,至少现在双线性刻度很快。不幸的是,这意味着用户无法将其全屏分辨率设置为低于其原始分辨率。

顺便说一句,我看到使用BufferedImage(从2毫秒到1毫秒)有一些非常显着的绘制性能提升,而VolatileImage(降到0.3毫秒)则更多,只要我有{{{ 1}}在VM参数中。但在全屏模式下,这些性能改进消失了(可能采用软件扩展解决方案)