Drawing to large BufferedImage, Direct3D pipeline slower then software pipeline?
Hi,
I've recently run into a problem where I'm rendering graphics too a large BufferedImage. Strangely what I've discovered is that using the Direct3D pipeline, which to my understanding is hardware accelerated, is very slow compared to disabling the Direct3D pipeline and other hardware acceleration.
The problem is disabling hardware acceleration slows every other aspect of my application down such as animations that use scaling, translation and alpha.
I use the VM option:
Code:
-Dsun.java2d.trace=count
To see what the problem might be in regards to hardware acceleration:
Code:
-Dsun.java2d.d3d=false
With Direct3D (hardware acceleration) disabled: (Fast)
Code:
205 calls to sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa, IntRgb)
208 calls to sun.java2d.loops.FillRect::FillRect(AnyColor, SrcNoEa, AnyInt)
204 calls to sun.java2d.loops.DrawLine::DrawLine(AnyColor, SrcNoEa, AnyInt)
205 calls to sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntRgb)
205 calls to sun.java2d.windows.GDIBlitLoops::Blit(IntRgb, SrcNoEa, "GDI")
1027 total calls to 5 different primitives
Code:
-Dsun.java2d.d3d=true
With Direct3D enabled: (Slow)
Code:
46 calls to sun.java2d.loops.DrawLine::DrawLine(AnyColor, SrcNoEa, AnyInt)
1 call to sun.java2d.d3d.D3DTextureToSurfaceBlit::Blit("D3D Texture", AnyAlpha, "D3D Surface")
44 calls to sun.java2d.d3d.D3DSwToSurfaceBlit::Blit(IntArgbPre, AnyAlpha, "D3D Surface")
50 calls to D3DFillRect
45 calls to sun.java2d.d3d.D3DRTTSurfaceToSurfaceBlit::Blit("D3D Surface (render-to-texture)", AnyAlpha, "D3D Surface")
1 call to sun.java2d.d3d.D3DSwToTextureBlit::Blit(IntArgbPre, SrcNoEa, "D3D Texture")
187 total calls to 6 different primitives
So given my SSCCE below, what might cause poor performance when using Direct3D while rendering to a large BufferedImage? I would if anything expect performance to be faster with hardware acceleration opposed to without it.
Thank you for you're help :)-:, this is really confusing to me and I need to have Direct3D enabled... Also strangely it looks like half my code is commented out but that's just a coloring error.
Try passing the VM option "-Dsun.java2d.d3d=true" and "-Dsun.java2d.d3d=false" at the command line to see the difference in performance.
SSCCE:
Code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
public class HardwareAcceleration extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
} catch(Exception err) {
err.printStackTrace();
}
new HardwareAcceleration();
}
});
}
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsConfiguration gc = env.getDefaultScreenDevice().getDefaultConfiguration();
BufferedImage drawSurface;
Graphics2D drawGraphics;
Point mouse = new Point(0,0);
PaintSurface canvas = new PaintSurface();
public HardwareAcceleration() {
/*
The BufferedImage to which graphics will be drawn too. The size is large
to demonstrate the sluggish drawing I experience curiously only when
not using the line "createBufferStrategy(2) or the command line argument "-Dsun.java2d.d3d=true".
*/
drawSurface = gc.createCompatibleImage(4000, 4000, Transparency.TRANSLUCENT);
drawGraphics = drawSurface.createGraphics();
setSize(600, 400);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
canvas.addMouseListener(new MouseListener());
canvas.addMouseMotionListener(new MouseListener());
add(canvas);
setVisible(true);
/*
The line below also solves the problem by indirectly disabling Direct3D.
*/
//createBufferStrategy(2);
}
class MouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
mouse = e.getPoint();
}
@Override
public void mouseDragged(MouseEvent e) {
/*
Here's where the problem occurs. Without the line
"createBufferStrategy(2)" drawing on an image of such a large
size is very slow. However with that line drawing is smooth and fast.
The problem is (1) I haven't the slightest clue why the line "createBufferStrategy(2)"
would solve this performance problem, maybe it enables some sort of hardware acceleration?
But i'm used to using "createBufferStrategy()" when active rendering using "getBufferStrategy().getDrawGraphics()"
so without drawing to the strategies draw graphics I'm not sure why this would effect anything.
(2) The line createBufferStrategy(2) seems to cause some other performance issues with
scaling and transparency animations where without it these animations are smooth.
My final goal is to figure out why drawing to this large image is slow without
the line "createBufferStrategy(2)" and how I might be able to speed it up without
it as it causes other problems.
*/
drawGraphics.drawLine(mouse.x, mouse.y, e.getX(), e.getY());
mouse = e.getPoint();
canvas.repaint();
}
}
class PaintSurface extends JPanel {
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setColor(Color.black);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.drawImage(drawSurface, 0, 0, this);
}
}
}