使用Java中的drawImage进行图像缩放的奇怪性能问题

时间:2015-02-27 11:01:40

标签: java image performance swing opengl

以下测试代码使用不同的图像缩放方法将随机生成的图像渲染四次到JFrame

import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.image.*;
import java.awt.geom. *;

public class Java2DImageBenchmark extends JFrame
{
    static int w = 1024;
    static int h = 1024;

    int run = 0;

    public void paint( Graphics g )
    {
        if( g instanceof Graphics2D )
        {
            final Graphics2D g2 = ( Graphics2D ) g;

            // create image with random noise in each run
            Random r = new Random();
            BufferedImage bi = g2.getDeviceConfiguration().createCompatibleImage( w / 3, h / 3 );
            for( int y = 0; y < h / 3; y++ )
                for( int x = 0; x < w / 3; x++ )
                    bi.setRGB( x, y, r.nextInt() );

            // scaling transformation
            AffineTransform s = AffineTransform.getScaleInstance( 3, 3 );

            long time = System.currentTimeMillis();

            // test runtimes of different scaling approaches
            switch( run )
            {
                case 0:
                    g2.drawImage( bi, new AffineTransformOp( s, AffineTransformOp.TYPE_NEAREST_NEIGHBOR ), 0, 0 );
                    System.out.println( "drawImage TYPE_NEAREST_NEIGHBOR: " + ( System.currentTimeMillis() - time ) + "ms" );
                    break;
                case 1:
                    g2.drawImage( bi, new AffineTransformOp( s, AffineTransformOp.TYPE_BILINEAR ), 0, 0 );
                    System.out.println( "drawImage TYPE_BILINEAR: " + ( System.currentTimeMillis() - time ) + "ms" );
                    break;
                case 2:
                    g2.drawImage( bi, new AffineTransformOp( s, AffineTransformOp.TYPE_BICUBIC ), 0, 0 );
                    System.out.println( "drawImage TYPE_BICUBIC: " + ( System.currentTimeMillis() - time ) + "ms" );
                    break;
                case 3:
                    BufferedImage biScaled = g2.getDeviceConfiguration().createCompatibleImage( w, h );
                    ( ( Graphics2D ) biScaled.getGraphics() ).drawImage( bi, new AffineTransformOp( s, AffineTransformOp.TYPE_BICUBIC ), 0, 0 );
                    g2.drawImage( biScaled, new AffineTransformOp( new AffineTransform(), AffineTransformOp.TYPE_NEAREST_NEIGHBOR ), 0, 0 );
                    System.out.println( "drawImage TYPE_BICUBIC prescaled: " + ( System.currentTimeMillis() - time ) + "ms" );
                    break;
                case 4:
                    System.exit( 0 );
            }
            ++run;
            repaint();
        }
        else
        {
            g.drawString( "this component needs a Graphics2D for painting", 2, this.getHeight() - 2 );
        }
    }

    public static void main( String[] args )
    {
        Java2DImageBenchmark f = new Java2DImageBenchmark();
        f.setSize( w, h );
        f.setVisible( true );
        f.repaint();
    }
}

在我的MacBook Pro上,当我在集成的Intel HD Graphics 4000和NVIDIA GeForce GT 650M(使用gfxCardStatus进行切换)之间切换时,得到两个非常不同的结果:

Intel HD Graphics 4000
======================
drawImage TYPE_NEAREST_NEIGHBOR:   11ms
drawImage TYPE_BILINEAR:         1281ms
drawImage TYPE_BICUBIC:          1198ms
drawImage TYPE_BICUBIC prescaled:  82ms

NVIDIA GeForce GT 650M
======================
drawImage TYPE_NEAREST_NEIGHBOR:   14ms
drawImage TYPE_BILINEAR:          138ms
drawImage TYPE_BICUBIC:           141ms
drawImage TYPE_BICUBIC prescaled:  80ms

如您所见,使用插值时,两个平台的性能差异很大。

经过测试的java版本已经1.7.0_761.8.0_31,结果几乎相同。在sun.java2d.opengltrue之间切换false也没有任何区别,我觉得有点令人惊讶,因为sun.java2d.opengl=false应该实际平衡两个显卡之间的软件渲染我的看法。

我发现这种行为,因为我的一个Java应用程序在使用Intel GPU的某些平台上速度非常慢。

但最后一个使用额外缓冲区将图像预分割到所需大小的测试用例是我真正不理解的。无论如何这是最快的。怎么会这样?

任何人都可以确认这种行为,并可能提供一些见解,这里实际发生了什么?上述基准对我来说绝对违反直觉。

0 个答案:

没有答案