JDK-4760752 : 1.4 REGRESSION: Drawing images with createCompatibleImage() is slow on 1.4
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.4.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2002-10-09
  • Updated: 2002-10-10
  • Resolved: 2002-10-10
Related Reports
Duplicate :  
Description

Name: jk109818			Date: 10/09/2002


FULL PRODUCT VERSION :
java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)

AND

java version "1.4.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-b21)
Java HotSpot(TM) Client VM (build 1.4.1-b21, mixed mode)

FULL OPERATING SYSTEM VERSION :

Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
Opaque images created with
GraphicsConfiguration.createCompatibleImage() draw slower
under JDK 1.4.

If you draw a rectangle and then draw opaque images
(created with createCompatibleImage()) on top of that
rectangle with ANTI_ALIASING turned ON, it is way slower
then drawing buffered images of type
(BufferedImage.TYPE_INT_RGB).

If you don't draw the rectangle createCompatibleImage() is
faster then doing new BufferedImage(). Notice that this
only applies to OPAQUE images.

Also note that this works fine under jdk1.3.1

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. USE jdk 1.4
2. compile the program
3. observe the time spent (printed to std out)
4. make RUN_TEST_CASE = TEST_CASE2
5. repeat steps 2-4




EXPECTED VERSUS ACTUAL BEHAVIOR :
Drawing with TEST_CASE1 (createCompatibleImage()) is way
slower than TEST_CASE2 (new BufferedImage()).

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;


/**
 *
 * Draws 30 images over a pink rectangle and measures the time it took
 * to draw the images. The time spent is send to stdout. The images
 * are created either by (1) createCompatibleImage() or
 * by (2) new BufferedImage(). In order to control how images are created,
 * modify RUN_TEST_CASE.
 *
 */
public class TestDrawImage extends JFrame
{


  public static int TEST_CASE1 = 1;
  public static int TEST_CASE2 = 2;
  

  /**
   *
   * make RUN_TEST_CASE be TEST_CASE1 to createCompatibleImage
   * make RUN_TEST_CASE be TEST_CASE2 to create a new BufferedImage.TYPE_INT_RGB
   *
   */
  public static int RUN_TEST_CASE = TEST_CASE1;


  public TestDrawImage()
  {
    getContentPane().add(new ImageDrawer());
    setBounds(100, 100, 800, 600);
    setVisible(true);
    addWindowListener(new WindowAdapter()
    {
      public void windowClosing(WindowEvent e)
      {
        System.exit(0);
      }
    });
  }



  public static void main(String[] args)
  {
    new TestDrawImage();
  }



  private class ImageDrawer extends JComponent
  {

    public ImageDrawer()
    {
      if (RUN_TEST_CASE == TEST_CASE1)
      {
        createCompatibleImage();
      }
      else if (RUN_TEST_CASE == TEST_CASE2)
      {
        createBufferedImage();
      }
    }

    public void paint(Graphics g)
    {
      Graphics2D g2d = (Graphics2D) g;

      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                           RenderingHints.VALUE_ANTIALIAS_ON);

      g2d.setColor(Color.pink);
      g2d.fill(new Rectangle2D.Double(0, 0, 500, 500));

      long startTime = System.currentTimeMillis();
      for (int i = 0; i < 30; i++)
      {
        g2d.drawImage(bi, new AffineTransform(), null);
      }
      long endTime = System.currentTimeMillis();
      long diff = endTime - startTime;
      System.out.println("TestDrawImage.java:: time spent is: " + diff);
    }


    private void createBufferedImage()
    {
      bi = new BufferedImage(WIDTH,
                             HEIGHT,
                             BufferedImage.TYPE_INT_RGB);
    }


    private void createCompatibleImage()
    {
      GraphicsEnvironment localGE =
        GraphicsEnvironment.getLocalGraphicsEnvironment();
      GraphicsDevice screenDevice = localGE.getDefaultScreenDevice();
      GraphicsConfiguration defaultGC =
        screenDevice.getDefaultConfiguration();

      bi = defaultGC.createCompatibleImage(WIDTH,
                                           HEIGHT,
                                           Transparency.OPAQUE);
    }

    private static final int WIDTH = 500;
    private static final int HEIGHT = 500;

    
    private BufferedImage bi = null;
  }
  
}

---------- END SOURCE ----------

CUSTOMER WORKAROUND :
Don't use createCompatibleImage(). Use new BufferedImage()
instead.

Release Regression From : 1.3.1
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.

(Review ID: 158757) 
======================================================================

Comments
EVALUATION I don't see the regression on my Win2K laptop. Please update with system/video info. ###@###.### 2002-10-09 It looks like the ddraw VRAM offscreen surface is getting punted into system memory because the AA fillRect causes MaskFills. Then we probably use the VRAM cached image from the CCI to render to the sysmem ddraw surface, which accounts for the slowdown. Probably should be using the BufImgSurfaceData instead as the source surface. ###@###.### 2002-10-09 This is a duplicate of 4631352: Translucent image copies to Swing back buffer slow in jdk1.4 (Windows only) The problem is described both above and in the evaluation fo 4631352; we do not differentiate between a DirectDraw buffer that lives in VRAM and a DirectDraw buffer that we have punted to system memory. Copies of VRAM- based images to a system memory-based buffer cause ddraw to do reads on the VRAM image followed by writes to the system memory buffer; the reads are incredible expensive and cause the kind of performance degredation seen in these bugs. Closing this bug as a duplicate of the earlier one. ###@###.### 2002-10-10
10-10-2002