icyphy / ptII

Ptolemy II is an open-source software framework supporting experimentation with actor-oriented design.
https://ptolemy.eecs.berkeley.edu/ptolemyII
Other
99 stars 43 forks source link

Diva's JCanvas handles double buffering incorrectly #67

Open cxbrooks opened 16 years ago

cxbrooks commented 16 years ago

Note: the issue was created automatically with bugzilla2github tool

Original bug ID: BZ#136 From: @cxbrooks Reported version: 7.0.beta CC: ian.brown@hsbcib.com, pt-dev@chess.eecs.berkeley.edu

cxbrooks commented 16 years ago

As pointed out by Ian Brown, Diva's JCanvas handles double buffering incorrectly.

Ian wrote: Christoper, I can confirm what you're seeing. I never did the check of changing the code - I was just code reading it and it looked wrong. It now looks like it's more broken than it first looked :) I guess there shouldn't be any harm in chopping out the double buffering code from JCanvas then given that it is not used and does not work.

As for the memory issues, I already run with 1Gig allocated for the JVM. The main issue is that I have lots of composite actors and each one opens in its own window which in Java 6 apparently has its own back-buffer. I guess a 'solution' may be to allow a composite actor to open in the same window as the parent when navigating into it (a bit like following a link in a browser - normally the new page will open in the same browser window unless you explicitly ask for a new window). To complete this paradigm, the toolbar would need a 'up' button which would display the containing composite or model if one exists.

Ian

Christopher wrote:

Hi Ian, Interesting!

I started looking into this. The double buffering code has been in diva.canvas.JCanvas since June, 1998.

http://java.sun.com/performance/reference/whitepapers/6_performance.html#2.4.4

says:

2.4.4 Swing's true double buffering

Swing's true double buffering has now been enabled. Swing used to provide double buffering on an application basis, it now provides it on a per-window basis and native exposed events are copied directly from the double buffer. This significantly improves Swing performance, especially on remote servers.

Please see the Scott Violet's Blog for full details.

http://weblogs.java.net/blog/zixle/archive/2005/04/no_more_gray_re_1.html

There is a bug that says this is fixed in Java 1.6: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4967886

I looked around and I can't be sure exactly when the Java release changed. The Java release notes for 1.5 and 1.6 are not much help. I'm just curious, do you have a reference for when the double buffering changed?

We are still supporing Java 1.5, so we might need to conditionalize this.

Putting a println statement before the if:

    System.out.println("JCanvas: isDoubleBuffered(): " +

isDoubleBuffered()); if (!isDoubleBuffered()) { Graphics2D g2d = (Graphics2D) g;

always yields "JCanvas: isDoubleBuffered(): false" under Windows XP on a HP laptop with Sun's Java 1.5.0_11 and 1.6.0_05. So, the offscreen code is not being used when I'm running. It might be different on a multiscreen device though.

Do you get something similar? On what platform and JVM are you running?

Also, if I changed the conditional to if (isDoubleBuffered()) { then I got horrible black boxes in the damage area.

Do you see something similar?

BTW - One hack is to increase the memory by using the -Xmx option to java. I'm fairly certain you know about this, but I thought I'd mention it. To increase the memory: bash-3.2$ export JAVAFLAGS=-Xmx666m bash-3.2$ $PTII/bin/vergil -v ../../ptolemy/domains/sdf/demo/Butterfly/Butterfly.xml

To verify how much memory, do View -> JVM Properties and look at the Max memory line at the top.

Still, I'm curious as to whether the double buffering is necessary and if it is right, so let me know if isDoubleBuffered() is returning true for you and what happens if you reverse the isDoubleBuffered() conditional.

_Christopher

Ian wrote: I have a small problem with Kepler / Ptolemy if I have too may windows open, or if I accidentally hit the maximize window button in that my PC hangs. This is seemingly due to memory issues in the Java VM. I have 3 monitors, so hitting the full-screen button creates a 3840 x 1024 window. To see what was using so much memory, I had a poke around in Diva and found some odd code in JCanvas.

JCanvas has the following code in the paint method:

        if (!isDoubleBuffered()) {
            Graphics2D g2d = (Graphics2D) g;

            // Clear the clip region to the background color
            g2d.setBackground(getBackground());

            if (_workaroundClearRectBug) {
                g2d.clearRect(0, 0, clip.width, clip.height);
            } else {
                g2d.clearRect(clip.x, clip.y, clip.width, clip.height);
            }

            // Draw directly onto the graphics pane
            if (paintAll) {
                _canvasPane.paint(g2d);
            } else {
                _canvasPane.paint(g2d, clip);
            }
        } else {

          // Get a new offscreen buffer if necessary. Clear the reference
            // to the off-screen buffer, so that the memory can be freed
            // if necessary by the GC and reallocated for the new buffer.
            if ((_offscreen == null) || (_offscreen.getWidth() != clip.widt\

h) || (_offscreen.getHeight() != clip.height)) { _offscreen = null; // in case GC needs it _offscreen = new BufferedImage(clip.width, clip.height, BufferedImage.TYPE_INT_RGB); }

            Graphics2D g2d = _offscreen.createGraphics();

        // ------------ code removed for brevity --------------
            // Blit it to the onscreen buffer
            g.drawImage(_offscreen, clip.x, clip.y, null);
        }

So, if the system is not keeping a backing buffer itself
(isDoubleBuffered() returns false) JCanvas draws directly to the screen.
If the system is keeping a backing buffer though then JCanvas creates
another backing buffer of it's own and uses that. It then blits
that to the system backing buffer ... which then in turn is
blitted to the screen. This makes no sense to me. If anything, the
logic should be reversed which would cause a backing buffer to be
always used regardless of whether the system has one or not. As it
stands now though, it would appear that we either use no backing
buffer, or we use 2 of them. Given that in Java 5 and above top-level
components are double buffered by default, Diva is always creating an
extra, unnecessary backing buffer.  It would appear that one could
simply delete all of the _offscreen code from JCanvas and it would
remain functionally the same in terms of when a
backing store is used. Am I missing something?

Ian