This discussion is archived
5 Replies Latest reply: Dec 22, 2011 7:14 AM by gimbal2 RSS

Bad Accelerated Paint Performance on Windows

wzberger Newbie
Currently Being Moderated
As you maybe know Direct3D acceleration is enabled by default. The test case below counts the maximum possible repaints for a simple JButton and prints the result as repaints/second at the console. Here are my results:

D3D_ENABLED = true, default font size -> 2.800 repaints/sec
D3D_ENABLED = true, font size 75 -> 418 repaints/sec

Sounds weird, but by disabling D3D the paint performance is much better.

D3D_ENABLED = false, default font size -> 6.019 repaints/sec
D3D_ENABLED = false, font size 75 -> 4.290 repaints/sec

As you can see with the default font size the non-accelerated painting performance has been doubled and with large font size the performance is around 10 times faster compared to accelerated results! The results are unchanged when disabling DirectDraw via "sun.java2d.noddraw=true". The test was made on Windows 7 with an AMD Radeon6770 and lasted graphics device driver - I've also noticed a similar behavior with a NVidia graphics card. So I wonder if this is known bug?

Test case:
public class PaintPerformanceTest extends JFrame
{
  private final static boolean D3D_ENABLED = true;
  private int paintCount;

  public static void main(String[] args)
  {
    System.setProperty("sun.java2d.d3d", D3D_ENABLED+"");
    EventQueue.invokeLater(new Runnable()
    {
      public void run()
      {
        new PaintPerformanceTest();
      }
    });
  }

  public PaintPerformanceTest()
  {
    final JButton button = new JButton("Button")
    {
      @Override
      protected void paintComponent(Graphics g)
      {
        super.paintComponent(g);
        paintCount++;
      }
    };
    //larger font size extremely slow down painting in accelerated mode 
    //button.setFont(new Font("Dialog", Font.PLAIN, 75));
    add(button);
    
    setTitle(getClass().getSimpleName());
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(300, 200);
    setLocationRelativeTo(null);
    setVisible(true);
    
    Thread t = new Thread(){
      @Override
      public void run()
      {
        System.err.println("Wait...");        
        int seconds = 5;
        PaintThread paintThread = new PaintThread(button);
        paintThread.start();
        try
        {
          Thread.sleep(seconds*1000);
        }
        catch (InterruptedException e)
        {
          e.printStackTrace();
        }
        paintThread.stopPainting();
        double fps = (paintThread.repaintCount*1000)/(double)paintThread.paintTime;
        System.err.format("Iterations: %2$d, Time: %1$d ms, repaints/sec: %3$.2f %n", paintThread.paintTime, paintThread.repaintCount, fps);
      }
    };
    t.start();
  } 
    
  class PaintThread extends Thread
  {
    private JComponent c;
    private int repaintCount;
    private boolean stopped;
    long start;
    long stop;
    long paintTime;
        
    public PaintThread(JComponent c)
    {
      this.c = c;
      repaintCount = 0;
    }
    
    @Override
    public synchronized void start()
    {
      start = System.currentTimeMillis();
      super.start();
    }
    
    public void stopPainting()
    {
      stopped = true; 
      stop = System.currentTimeMillis();
      paintTime = stop-start;
    }
    
    public void run()
    {
      while (!stopped)
      {
        try
        {
          EventQueue.invokeAndWait(new Runnable()
          {
            public void run()
            {
              c.repaint();
              repaintCount++;
            }
          });
        }
        catch (Exception e)
        {
          e.printStackTrace();
        }
      } 
    }    
  }  
}
  • 1. Re: Bad Accelerated Paint Performance on Windows
    gimbal2 Guru
    Currently Being Moderated
    These results you are showing here are weird, I wonder if there is not a flaw in the testing method somewhere. Like this you do an insane amount of repaints() each second, way more than what is realistic. I wouldn't be surprised if excessive repainting can actually conflict with the Direct3D pipeline.

    That being said, I'm curious what happens when you enable the OpenGL pipeline.
  • 2. Re: Bad Accelerated Paint Performance on Windows
    wzberger Newbie
    Currently Being Moderated
    Well, I've struggled about the issue by optimizing JTable cell renderer. For a larger JTable with different data types the results are more realistic - around 60 repaints/sec accelerated and 120 repaints/sec non-accelerated. Because of the worse performance with large fonts, I have the feeling that the issue has to do with glyph painting. Anyway, here are the test results with OpenGl enabled:

    default font size -> 1.338 repaints/sec
    large font size -> 472 repaints/sec
  • 3. Re: Bad Accelerated Paint Performance on Windows
    gimbal2 Guru
    Currently Being Moderated
    Even slower. Curious.
    Because of the worse performance with large fonts, I have the feeling that the issue has to do with glyph painting.
    You may well be correct, Java2D hardware acceleration has always been sketchy and very much system dependent. You can enable logging ( -Dsun.java2d.trace=log ) that shows what drawing calls are performed, that way you can see when something is rendered through Direct3D and when something is rendered through the software fallback. I'm betting a lot is going through the fallback routines.

    Changing look & feel might also impact by the way. Try with a Nimbus look & feel for example. I believe that L&F was designed to work with the hardware acceleration drawing path.


    But yeah, Java2D/Swing is basically buried now that JavaFX 2 has arrived.
  • 4. Re: Bad Accelerated Paint Performance on Windows
    wzberger Newbie
    Currently Being Moderated
    Currently JavaFX is not an option. I don't agree that Swing is buried - too many apps are in use and migrating to JavaFX almost means to start from scratch. Additionally, currently it's not quite clear if this is a bug or not and it's also possible that the Java2D team ported this behavior by copying some code into the Prism engine. Anyway, here are the results for Nimbus.

    D3D enabled, default font size -> 192 repaints/sec
    D3D disabled, default font size -> 534 repaints/sec

    D3D enabled, font size 75 -> 136 repaints/sec
    D3D disabled, font size 75 -> 524 repaints/sec

    Here's the log result for Metal with D3D enabled:

    D3DDrawGlyphs
    D3DDrawRect
    sun.java2d.d3d.D3DRTTSurfaceToSurfaceBlit::Blit("D3D Surface (render-to-texture)", AnyAlpha, "D3D Surface")
    sun.java2d.d3d.D3DRTTSurfaceToSurfaceBlit::Blit("D3D Surface (render-to-texture)", AnyAlpha, "D3D Surface")
    sun.java2d.d3d.D3DRTTSurfaceToSurfaceBlit::Blit("D3D Surface (render-to-texture)", AnyAlpha, "D3D Surface")
    sun.java2d.d3d.D3DRTTSurfaceToSurfaceBlit::Blit("D3D Surface (render-to-texture)", AnyAlpha, "D3D Surface")
    sun.java2d.d3d.D3DRTTSurfaceToSurfaceBlit::Blit("D3D Surface (render-to-texture)", AnyAlpha, "D3D Surface")
    sun.java2d.d3d.D3DRTTSurfaceToSurfaceBlit::Blit("D3D Surface (render-to-texture)", AnyAlpha, "D3D Surface")
    D3DDrawGlyphs
    D3DDrawRect
    sun.java2d.d3d.D3DRTTSurfaceToSurfaceBlit::Blit("D3D Surface (render-to-texture)", AnyAlpha, "D3D Surface")
    sun.java2d.d3d.D3DRTTSurfaceToSurfaceBlit::Blit("D3D Surface (render-to-texture)", AnyAlpha, "D3D Surface")
    sun.java2d.d3d.D3DRTTSurfaceToSurfaceBlit::Blit("D3D Surface (render-to-texture)", AnyAlpha, "D3D Surface")
    sun.java2d.d3d.D3DRTTSurfaceToSurfaceBlit::Blit("D3D Surface (render-to-texture)", AnyAlpha, "D3D Surface")
    sun.java2d.d3d.D3DRTTSurfaceToSurfaceBlit::Blit("D3D Surface (render-to-texture)", AnyAlpha, "D3D Surface")
    sun.java2d.d3d.D3DRTTSurfaceToSurfaceBlit::Blit("D3D Surface (render-to-texture)", AnyAlpha, "D3D Surface")
    ...
  • 5. Re: Bad Accelerated Paint Performance on Windows
    gimbal2 Guru
    Currently Being Moderated
    I'm stumped.

    BTW: the fact that something is still used doesn't mean much in development land. Cobol is still used. Swing isn't developed anymore, you can call it either "stable" or "buried". Now that JavaFX is in the spotlight, I personally tip the scale to buried.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points