JDK-6772132 : D3D: uncached Image scaling performance regression
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 6u10
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2008-11-17
  • Updated: 2011-02-16
  • Resolved: 2008-11-18
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
Image rendering in 1.6.0 update 10 has become about 10 times slower when compared to rendering speed in 1.6.0 update 07.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the included test code. Move the zoom slider back and forth until the average image paint time is printed in the console. In 1.6.0_10 this may take a while, in 1.6.0_07 it will be much faster (about 10 times faster when in full-screen).

I could reproduce average paint times of about 100 millisec. for update 10 (both in initial frame size or full-screen frame) and between 2 millisec.(initial frame size) and 10  millisec. (full-screen) for update 07.

(Remark: Running this test in 1.7.0-ea-b39 seems to be almost impossible)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package test;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;

/**
 *
 */
public class ImageTest extends JFrame {
    AffineTransform Trns;
    BufferedImage Img;

    JSlider VwZmSlider;
    JPanel PaintPanel;

    protected void setZoom(double newZoom) {
        Trns.setToScale(newZoom, newZoom);
    }

    public ImageTest() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Trns = new AffineTransform();
        Img = new BufferedImage(6500, 2500, BufferedImage.TYPE_3BYTE_BGR);

        Graphics g = Img.getGraphics();
        try {
            for (int i = 0; i < 6500; i += 50) {
                g.setColor(Color.WHITE);
                g.drawLine(0, i, 6500, i);
                g.drawLine(i, 0, i, 2500);
            }
        } finally {
            g.dispose();
        }

        PaintPanel = new JPanel() {
            private int paintCount;
            private long paintTime;

            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g;

                g2d.transform(Trns);
                long time = -System.nanoTime();
                g2d.drawImage(Img, 0, 0, this);
                time += System.nanoTime();
                paintTime += time;
                paintCount++;

                if (paintCount == 1) {
                    System.out.println("First paint time = " + (paintTime / paintCount) + " nanosec");
                }
                if ((paintCount % 100) == 0) {
                    System.out.println("Average image paint time on " + paintCount + " paints = " + (paintTime / paintCount) + " nanosec");
                }
            }
        };

        Dimension Size = new Dimension(500, 500);
        PaintPanel.setPreferredSize(Size);
        PaintPanel.setMinimumSize(Size);
        PaintPanel.setMaximumSize(Size);

        VwZmSlider = new JSlider(0, 100, 50);
        VwZmSlider.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent changeEvent) {
                int val = VwZmSlider.getValue();
                switch (val) {
                    case 0:
                        setZoom(0.1);
                        break;

                    case 15:
                        setZoom(0.5);
                        break;

                    case 30:
                        setZoom(0.75);
                        break;

                    case 50:
                        setZoom(1.0);
                        break;

                    case 70:
                        setZoom(1.5);
                        break;

                    case 85:
                        setZoom(2.0);
                        break;

                    case 100:
                        setZoom(3.0);
                        break;

                    default:
                        if (val > 0 && val < 15) {
                            setZoom(((0.39 / 14.0) * (val - 1)) + 0.1);
                        } else if (val > 15 && val < 30) {
                            setZoom(((0.24 / 14.0) * (val - 15)) + 0.5);
                        } else if (val > 30 && val < 50) {
                            setZoom(((0.24 / 19.0) * (val - 30)) + 0.75);
                        } else if (val > 50 && val < 70) {
                            setZoom(((0.49 / 19.0) * (val - 50)) + 1.0);
                        } else if (val > 70 && val < 85) {
                            setZoom(((0.49 / 14.0) * (val - 70)) + 1.5);
                        } else {
                            setZoom(((0.99 / 14.0) * (val - 85)) + 2.0);
                        }
                        break;
                }
                PaintPanel.repaint();
            }
        });

        JPanel FillPanel = new JPanel();
        FillPanel.setLayout(new BorderLayout());

        FillPanel.add(PaintPanel, BorderLayout.CENTER);
        FillPanel.add(VwZmSlider, BorderLayout.SOUTH);

        getContentPane().add(FillPanel);
        pack();
        show();
    }

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

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

Release Regression From : 6u6
The above release value was the last known release where this 
bug was not reproducible. Since then there has been a regression.

Comments
EVALUATION Ok, we found what is the cause of the difference in performance. I have a very high-end video board, which allows textures up to 8192x8192, so the image created by this test can be cached in a texture. On other boards which may have lower max texutre size (more like 4096x4096), the image won't be cached and we have to go through a slow path (covered in 6652116) every time we render the image. So the work around is to break your image into smaller ones, or disable the d3d pipeline (this can be done for Applet with the new plugin, or JNLP app). Also, regarding the OOME on jdk7. 6u10 has a fix for 6739267: D3D/OGL: add missing ThreeByteBgr to texture upload blit loop which reduces the amount of heap needed to scale this ThreeByteBgr image. This fix hasn't made it into 7 main tree yet (it's in the 2d gate), once it does you'll see the same behavior as in 6u10. I'm closing this bug as a duplicate of 6652116.
18-11-2008

EVALUATION I can't reproduce this on my system. Performance would certainly depend on the video board, but I wouldn't expect it to be slower than 6u7 except in some pathological cases. Please provide hw configuration data by setting this env. variable: #> set J2D_TRACE_LEVEL=4 #> java ImageTest and collecting the output on the console. On my system: [I] OS Version = OS_WINXP Pro [I] CheckAdaptersInfo [I] ------------------ [I] Adapter Ordinal : 0 [I] Adapter Handle : 0x10001 [I] Description : NVIDIA GeForce 8800 GTS 512 [I] GDI Name, Driver : \\.\DISPLAY1, nv4_disp.dll [I] Vendor Id : 0x10de [I] Device Id : 0x0600 [I] SubSys Id : 0x58110de [I] Driver Version : 6.14.11.7813 [I] GUID : {D7B71E3E-4540-11CF-EB6D-8A2503C2CB35} [I] D3DPPLM::CheckDeviceCaps: adapter 0: Passed #>/cygdrive/m/re/1.6.0_07/latest/binaries/windows-i586/bin/java ThreeByteBgrPerfTest First paint time = 1624028 nanosec Average image paint time on 100 paints = 1429160 nanosec Average image paint time on 200 paints = 1725501 nanosec Average image paint time on 300 paints = 1648903 nanosec Average image paint time on 400 paints = 1595133 nanosec Average image paint time on 500 paints = 1569980 nanosec Average image paint time on 600 paints = 1546066 nanosec Average image paint time on 700 paints = 1540596 nanosec #>/cygdrive/m/re/1.6.0_10/latest/binaries/windows-i586/bin/java ThreeByteBgrPerfTest First paint time = 90756328 nanosec Average image paint time on 100 paints = 1852021 nanosec Average image paint time on 200 paints = 944742 nanosec Average image paint time on 300 paints = 643873 nanosec Average image paint time on 400 paints = 490037 nanosec Average image paint time on 500 paints = 398535 nanosec Average image paint time on 600 paints = 337678 nanosec Average image paint time on 700 paints = 294435 nanosec Average image paint time on 800 paints = 261264 nanosec Average image paint time on 900 paints = 235403 nanosec Average image paint time on 1000 paints = 214817 nanosec Average image paint time on 1100 paints = 197363 nanosec Average image paint time on 1200 paints = 182900 nanosec Sure, the initial paint is slower because we first upload the image into a texture (and this operation may be slower than in 6u7, see 6652116), but subsequent ones are very fast. And this benchmark is not a very good one, counting performance of a single draw image (and w/o a Toolkit.sync()) doesn't make a lot of sense. One should use J2DBench for better Java2D performance measurements: http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/2201dad60231/src/share/demo/java2d/J2DBench/
18-11-2008