快速Java2D硬件缩放图像

时间:2023-01-31 21:54:01

I am trying to scale up a backbuffer using Java2D with some sort of decent anti-aliased interpolation (such as bilinear) at runtime. The idea is that I render the scene to this image, and then scale up the image in fullscreen mode to match whatever resolution the user has.

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

Note that fullscreen mode is important. This does not occur in windowed mode.

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

Is there a fast way of doing this using hardware scaling? Javadocs suggest that it exists (-Dsun.java2d.ddscale=true) but it is having no effect for me.

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

Here is the code:

这是代码:

// 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);

And the results:

结果如下:

  • Nearest Neighbour (about 2ms)
  • 最近邻(约2ms)

  • Bilinear (about 40ms)
  • 双线性(约40ms)

  • Bicubic (about 140ms)
  • 双立方(约140ms)

The image is a TYPE_INT_RGB opaque BufferedImage and I am drawing onto an AWT Canvas.

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

Other things I have tried:

我尝试过的其他事情:

  • VolatileImage (no performance change)
  • VolatileImage(无性能变化)

  • Dsun.java2d.ddscale=true (no change)
  • Dsun.java2d.ddscale = true(无变化)

  • Dsun.java2d.opengl=true (about 3x slower on all commands)
  • Dsun.java2d.opengl = true(所有命令慢约3倍)

  • AffineTransform (no change)
  • AffineTransform(无变化)

  • createBufferStrategy and "pre-scaling" by calling Graphics2D.scale (much slower, scales every draw call instead of 1 large buffer). Note that the BufferStrategy without scaling offers no speed improvement anyways.
  • createBufferStrategy和通过调用Graphics2D.scale“预缩放”(慢得多,缩放每个绘制调用而不是1个大缓冲区)。请注意,没有缩放的BufferStrategy无论如何都不会提高速度。

  • JPanel instead of Canvas (about 1.5x slower)
  • JPanel而不是Canvas(慢约1.5倍)

  • imgScalr "library" (this just calls g.drawImage exactly as I have it above)
  • imgScalr“library”(这只是调用g.drawImage,就像我上面一样)

Some other useful notes:

其他一些有用的说明:

  • buffer_.getCapabilities(gc).isAccelerated() returns false (in windowed mode it is true)
  • buffer_.getCapabilities(gc).isAccelerated()返回false(在窗口模式下为true)

  • This is legacy code, I have newer code that is all GL which does the scaling very quick, but don't want to have to rewrite the legacy program. Suggests that my hardware does in fact support HW scaling of images.
  • 这是遗留代码,我有更新的代码,所有GL都可以非常快速地进行扩展,但不想重写遗留程序。建议我的硬件实际上支持图像的硬件缩放。

  • AMD HD5770 graphics card
  • AMD HD5770显卡

  • Windows 7 latest Java 8 running as JVM.
  • Windows 7最新的Java 8作为JVM运行。

Thanks for any help. At this point, I am sadly considering converting everything over to GL just for this one thing... there must be an answer though!

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

2 个解决方案

#1


0  

While I regard you approach technically feasible, I wonder why you are so set on rendering in a fixed resolution.

虽然我认为你在技术上是可行的,但我想知道你为什么这么做以固定分辨率的渲染。

From a graphics quality standpoint, things should be rendered to the target resolution right away, eliminating the scaling completely. I realize that bitmap graphics (as in tiles etc.) will need to be scaled at some point, only I don't see why this needs to be done on the critical path (in realtime). My preferred aproach to this would be to pre-scale bitmaps to their required resolutions once (then either keep them cached scaled in memory or even on disk, depending which is more feasible).

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

There are a few things you may want to check, ensure that the image type used internally is compatible with the rendering surface (instead of using hardcoded TYPE_INT_RGB, create back buffers using a variant of createCompatibleImage, to ensure no format conversions are necessary). Also there is a whole buch of options that can alter what Graphics2D uses under the hood: http://docs.oracle.com/javase/7/docs/technotes/guides/2d/flags.html.

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

Finally, you may want to check that you aren't doing any of the "no go" things with your buffered images, like directly accessing the underlying buffer arrays (Can't accelerate pixel-modified BufferedImages), which interferes with javas ability to use hardware acceleration.

最后,您可能想要检查您是否正在使用缓冲图像执行任何“禁止”操作,例如直接访问底层缓冲区阵列(无法加速像素修改的BufferedImages),这会干扰javas的能力使用硬件加速。

#2


0  

I have yet to get full-screen exclusive mode to work in the above case, but I do have a workaround.

我还没有得到全屏独占模式在上面的情况下工作,但我有一个解决方法。

Stay in windowed mode, set the window size to match the size of the screen, set its position to graphicsDevice.getDefaultConfiguration().getBounds() and then setUndecorated(true). Finally, use java.awt.Robot to confine the mouse pointer to the window.

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

Not ideal, but visually it's indistinguishable from fullscreen and at least now the bilinear scale is fast. Unfortunately it means users cannot set their fullscreen resolution lower than their native resolution.

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

As an aside, I am seeing some pretty significant draw performance improvements using BufferedImage (drops from 2ms to 1ms) and even more with VolatileImage (drops to 0.3ms) provided that I had -Dsun.java2d.accthreshold=0 in the VM arguments. But in fullscreen mode these performance improvements vanished (likely resorting to software scaling solution)

顺便说一句,我看到使用BufferedImage(从2ms到1ms下降)的一些非常显着的绘制性能改进,甚至更多的VolatileImage(下降到0.3ms),前提是我在VM参数中有-Dsun.java2d.accthreshold = 0。但在全屏模式下,这些性能改进消失了(可能采用软件扩展解决方案)

#1


0  

While I regard you approach technically feasible, I wonder why you are so set on rendering in a fixed resolution.

虽然我认为你在技术上是可行的,但我想知道你为什么这么做以固定分辨率的渲染。

From a graphics quality standpoint, things should be rendered to the target resolution right away, eliminating the scaling completely. I realize that bitmap graphics (as in tiles etc.) will need to be scaled at some point, only I don't see why this needs to be done on the critical path (in realtime). My preferred aproach to this would be to pre-scale bitmaps to their required resolutions once (then either keep them cached scaled in memory or even on disk, depending which is more feasible).

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

There are a few things you may want to check, ensure that the image type used internally is compatible with the rendering surface (instead of using hardcoded TYPE_INT_RGB, create back buffers using a variant of createCompatibleImage, to ensure no format conversions are necessary). Also there is a whole buch of options that can alter what Graphics2D uses under the hood: http://docs.oracle.com/javase/7/docs/technotes/guides/2d/flags.html.

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

Finally, you may want to check that you aren't doing any of the "no go" things with your buffered images, like directly accessing the underlying buffer arrays (Can't accelerate pixel-modified BufferedImages), which interferes with javas ability to use hardware acceleration.

最后,您可能想要检查您是否正在使用缓冲图像执行任何“禁止”操作,例如直接访问底层缓冲区阵列(无法加速像素修改的BufferedImages),这会干扰javas的能力使用硬件加速。

#2


0  

I have yet to get full-screen exclusive mode to work in the above case, but I do have a workaround.

我还没有得到全屏独占模式在上面的情况下工作,但我有一个解决方法。

Stay in windowed mode, set the window size to match the size of the screen, set its position to graphicsDevice.getDefaultConfiguration().getBounds() and then setUndecorated(true). Finally, use java.awt.Robot to confine the mouse pointer to the window.

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

Not ideal, but visually it's indistinguishable from fullscreen and at least now the bilinear scale is fast. Unfortunately it means users cannot set their fullscreen resolution lower than their native resolution.

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

As an aside, I am seeing some pretty significant draw performance improvements using BufferedImage (drops from 2ms to 1ms) and even more with VolatileImage (drops to 0.3ms) provided that I had -Dsun.java2d.accthreshold=0 in the VM arguments. But in fullscreen mode these performance improvements vanished (likely resorting to software scaling solution)

顺便说一句,我看到使用BufferedImage(从2ms到1ms下降)的一些非常显着的绘制性能改进,甚至更多的VolatileImage(下降到0.3ms),前提是我在VM参数中有-Dsun.java2d.accthreshold = 0。但在全屏模式下,这些性能改进消失了(可能采用软件扩展解决方案)