Hmm, interesting idea.

This is a prototype patch. Try it out and let me know how it goes.

-- Noel Grandin

On 2012-01-20 11:09, Piotr Kołaczkowski wrote:
Hi,

Is there support for explicit double-buffering of components (especially windows) like it is in Swing? Currently I faced another performance problem - imagine a top level Window with a one single Frame open in it. The Window contains an animation, that needs to be repainted at >30 FPS. When I issue the repaint, not only the window gets repainted, but also the parts of the frame that happened to be inside the repaint region (if the user shadows a part of the animation with the frame, the frame gets the repaints). For complex Frames with lots of components inside them, it may be slow. And it is not needed, because I actually haven't changed anything inside the frame, so it is perfect case for double buffering and drawing the whole frame with a single drawImage statement.

So, is there a workaround now for this? Is this planned?

Regards,
Piotr

Index: Component.java
===================================================================
--- Component.java      (revision 1233880)
+++ Component.java      (working copy)
@@ -17,8 +17,10 @@
 package org.apache.pivot.wtk;
 
 import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
 import java.awt.Rectangle;
 import java.awt.Shape;
+import java.awt.Transparency;
 import java.awt.geom.AffineTransform;
 import java.util.Iterator;
 
@@ -629,6 +631,11 @@
     // The component's layout-valid state
     private boolean valid = false;
 
+    // The component's double-buffering buffer and flags
+    private boolean doubleBuffering = false;
+    private java.awt.image.BufferedImage doubleBufferImage = null;
+    private boolean doubleBufferedRepaintRequired = false;
+
     // The component's location, relative to the parent's origin
     private int x = 0;
     private int y = 0;
@@ -1958,6 +1965,9 @@
         // Clear the preferred size and baseline
         preferredSize = null;
         baseline = -1;
+        if (doubleBuffering) {
+            doubleBufferImage = null;
+        }
 
         if (parent != null) {
             parent.invalidate();
@@ -2045,6 +2055,9 @@
      */
     public void repaint(int x, int y, int width, int height, boolean 
immediate) {
         Container.assertEventDispatchThread(this);
+        if (doubleBuffering) {
+            doubleBufferedRepaintRequired = true;
+        }
         if (parent != null) {
             // Constrain the repaint area to this component's bounds
             int top = y;
@@ -2089,13 +2102,50 @@
      */
     @Override
     public void paint(Graphics2D graphics) {
-        skin.paint(graphics);
+        if (!doubleBuffering) {
+            skin.paint(graphics);
+        } else {
+            if (doubleBufferImage == null) {
+                GraphicsConfiguration gc = graphics.getDeviceConfiguration();
+                doubleBufferImage = gc.createCompatibleImage(getWidth(), 
getHeight(),
+                        Transparency.OPAQUE);
+                doubleBufferedRepaintRequired = true;
+            }
+            // TODO use clipbounds
+            Graphics2D bufferedImageGraphics = 
(Graphics2D)doubleBufferImage.getGraphics();
+            try {
+                if (doubleBufferedRepaintRequired) {
+                    skin.paint(bufferedImageGraphics);
+                    doubleBufferedRepaintRequired = false;
+                }
+                graphics.drawImage(doubleBufferImage, 0, 0, null);
+            } finally {
+                bufferedImageGraphics.dispose();
+            }
+
+        }
     }
 
+    public boolean isDoubleBuffered() {
+        return doubleBuffering;
+    }
+
+    public void setDoubleBuffered(boolean b) {
+       doubleBuffering = b;
+       if (b) {
+           invalidate();
+       } else {
+           doubleBufferImage = null;
+           doubleBufferedRepaintRequired = false;
+       }
+    }
+
     /**
      * Creates a graphics context for this component. This graphics context
      * will not be double buffered. In other words, drawing operations on it
      * will operate directly on the video RAM.
+     * <p>
+     * Primarily used by ScrollPaneSkin to optimise scrolling.
      *
      * @return
      * A graphics context for this component, or <tt>null</tt> if this
@@ -2134,6 +2184,7 @@
             graphics.clipRect(0, 0, getWidth(), getHeight());
         }
 
+        doubleBufferedRepaintRequired = true;
         return graphics;
     }
 

Reply via email to