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;
}