This discussion is archived
0 Replies Latest reply: Feb 2, 2011 2:50 AM by 836216 RSS

Drawing slowdown after showing popup

836216 Newbie
Currently Being Moderated
Hi,
i have found mysterious slowdown in graphic drawing after showing popup that exits frame borders. Don't know if this is a bug or i'm doing something wrong. Can anyone check this?

It is reproducible with AMD(ati) chips, don't know about others. Adding -Dsun.java2d.d3d=false makes drawing slower, but removes slowdown after popup
Steps to reproduce:
1. Start the program, it will output in console time used for every repaint
2. Right click near to the bottom edge of the frame to open popup. Popup must be opened partially outside the frame, openning in center of the frame doesn't reproduce anything.
3. Look at the repainting times in console after popup

I have the following results:
time to draw: 0.079728
time to draw: 0.064673
time to draw: 0.157063
time to draw: 0.131399
Showing popup
time to draw: 94.156793
time to draw: 40.368163
time to draw: 43.982313
time to draw: 47.154361

Times with -Dsun.java2d.d3d=false are:
time to draw: 4.288254
time to draw: 5.001366
time to draw: 4.158566
time to draw: 5.349709
time to draw: 4.113739

This bug makes accelerated drawing 10 times slower than without acceleration :(


Here is the code to reproduce the issue:
package bug.test;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.JPopupMenu;
import javax.swing.JMenuItem;
import javax.swing.JMenu;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Point;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.VolatileImage;

public class BugTestFrame extends JFrame {
    public BugTestFrame() {
        super("Bug test");
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setContentPane(new DrawablePanel());
    }

    private static class DrawablePanel extends JComponent implements MouseMotionListener, MouseListener {
        private VolatileImage backBuffer;
        private Point mousePosition = new Point(0, 0);
        private int staticContentRedraws;
        private int dynamicContentRedraws;

        public DrawablePanel() {
            addMouseMotionListener(this);
            addMouseListener(this);
        }

        @Override
        public void paintComponent(Graphics g) {
            long startTime = System.nanoTime();
            reinitBackBufferIfNecessary();
            redrawStaticContent(g);
            redrawDynamicContent(g);
            System.out.println("time to draw: " + ((System.nanoTime() - startTime) / 1000000d));
        }

        private void reinitBackBufferIfNecessary() {
            if (backBuffer == null || backBuffer.getHeight() != getHeight() || backBuffer.getWidth() != getWidth()) {
                createBackBuffer();
            }
        }

        private void redrawStaticContent(Graphics g) {
            do {
                int valCode = backBuffer.validate(getGraphicsConfiguration());
                if (valCode == VolatileImage.IMAGE_RESTORED) {
                    redrawDataOntoBackBuffer();
                } else if (valCode == VolatileImage.IMAGE_INCOMPATIBLE) {
                    createBackBuffer();
                    redrawDataOntoBackBuffer();
                }
                g.drawImage(backBuffer, 0, 0, this);
            }
            while (backBuffer.contentsLost());
        }

        private void createBackBuffer() {
            if (backBuffer != null) {
                backBuffer.flush();
                backBuffer = null;
            }
            backBuffer = createVolatileImage(getWidth(), getHeight());
        }

        private void redrawDataOntoBackBuffer() {
            Graphics gBB = backBuffer.createGraphics();
            try {
                gBB.setColor(Color.WHITE);
                gBB.fillRect(0, 0, backBuffer.getWidth(), backBuffer.getHeight());
                gBB.setColor(Color.GRAY.brighter());
                for (int h = 15; h < backBuffer.getHeight(); h += 15) {
                    gBB.drawLine(0, h, backBuffer.getWidth(), h);
                }
                for (int w = 15; w < backBuffer.getWidth(); w += 15) {
                    gBB.drawLine(w, 0, w, getHeight());
                }
                ++staticContentRedraws;
            } finally {
                gBB.dispose();
            }
        }

        private void redrawDynamicContent(Graphics g) {
            g.drawLine(0, mousePosition.y, getWidth(), mousePosition.y);
            g.drawLine(mousePosition.x, 0, mousePosition.x, getHeight());
            ++dynamicContentRedraws;
            g.drawString("Static content redraws: " + staticContentRedraws, 10, 10);
            g.drawString("Dynamic content redraws: " + dynamicContentRedraws, 10, 30);
        }

        private void showPopup(int x, int y) {
            JPopupMenu popup = new JPopupMenu("popup menu");
            for (int i = 1; i <= 5; i++) {
                JMenuItem menuItem = new JMenuItem("item" + i);
                popup.add(menuItem);
            }
            popup.show(this, x, y);
            System.out.println("Showing popup");
        }

        public void mouseDragged(MouseEvent e) {
            mousePosition.x = e.getX();
            mousePosition.y = e.getY();
            repaint();
        }

        public void mouseMoved(MouseEvent e) {
            mousePosition.x = e.getX();
            mousePosition.y = e.getY();
            repaint();
        }

        public void mouseClicked(MouseEvent e) {
        }

        public void mousePressed(MouseEvent e) {
            if (e.isPopupTrigger()) {
                showPopup(e.getX(), e.getY());
            }
        }

        public void mouseReleased(MouseEvent e) {
            if (e.isPopupTrigger()) {
                showPopup(e.getX(), e.getY());
            }
        }

        public void mouseEntered(MouseEvent e) {
        }

        public void mouseExited(MouseEvent e) {
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                BugTestFrame frame = new BugTestFrame();
                frame.pack();
                frame.setSize(800, 600);
                frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
                frame.setVisible(true);
            }
        });
    }
}

Legend

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