Hi,
Attached is a patch to optimize ellipse drawing in java2d. I'm seeing a
~25% speed boost from it on both draw and fill.
Also, ignore my earlier patch re alpha composite; I realised that it
doesn't work with gradients/textures, and am working on a better patch.
Francis
2006-07-12 Francis Kung <[EMAIL PROTECTED]>
* gnu/java/awt/peer/gtk/CairoGraphics2D.java: Organized imports.
(cairoArc): New native method.
(cairoRestore): New native method.
(cairoSave): New native method.
(cairoScale): New native method.
(createPath): New method to centralize code from draw and fill.
(draw): Modified to use createPath method.
(fill): Modified to use createPath method.
* include/gnu_java_awt_peer_gtk_CairoGraphics2D.h: Added
function declarations.
* native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c
(Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoScale): New
method.
(Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoSave): New
method.
(Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoArc): New
method.
Index: gnu/java/awt/peer/gtk/CairoGraphics2D.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java,v
retrieving revision 1.29
diff -u -r1.29 CairoGraphics2D.java
--- gnu/java/awt/peer/gtk/CairoGraphics2D.java 30 Jun 2006 17:39:14 -0000 1.29
+++ gnu/java/awt/peer/gtk/CairoGraphics2D.java 12 Jul 2006 18:18:58 -0000
@@ -40,8 +40,8 @@
import gnu.java.awt.ClasspathToolkit;
-import java.awt.AlphaComposite;
import java.awt.AWTPermission;
+import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
@@ -53,11 +53,11 @@
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Paint;
+import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
-import java.awt.Polygon;
import java.awt.TexturePaint;
import java.awt.Toolkit;
import java.awt.font.FontRenderContext;
@@ -66,6 +66,7 @@
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
+import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.PathIterator;
@@ -322,6 +323,11 @@
* Set the current transform matrix
*/
private native void cairoSetMatrix(long pointer, double[] m);
+
+ /**
+ * Scaling method
+ */
+ private native void cairoScale(long pointer, double x, double y);
/**
* Set the compositing operator
@@ -369,6 +375,18 @@
*/
private native void cairoRectangle(long pointer, double x, double y,
double width, double height);
+
+ /**
+ * Appends an arc to the current path
+ */
+ private native void cairoArc(long pointer, double x, double y,
+ double radius, double angle1, double angle2);
+
+ /**
+ * Save / restore a cairo path
+ */
+ private native void cairoSave(long pointer);
+ private native void cairoRestore(long pointer);
/**
* New current path
@@ -920,36 +938,71 @@
return;
}
- cairoNewPath(nativePointer);
-
- if (s instanceof Rectangle2D)
- {
- Rectangle2D r = (Rectangle2D) s;
- cairoRectangle(nativePointer, shifted(r.getX(), shiftDrawCalls),
- shifted(r.getY(), shiftDrawCalls), r.getWidth(),
- r.getHeight());
- }
- else
- walkPath(s.getPathIterator(null), shiftDrawCalls);
+ createPath(s);
cairoStroke(nativePointer);
}
public void fill(Shape s)
{
+ createPath(s);
+
+ double alpha = 1.0;
+ if (comp instanceof AlphaComposite)
+ alpha = ((AlphaComposite) comp).getAlpha();
+ cairoFill(nativePointer, alpha);
+ }
+
+ private void createPath(Shape s)
+ {
cairoNewPath(nativePointer);
+
+ // Optimize rectangles, since there is a direct Cairo function
if (s instanceof Rectangle2D)
{
- Rectangle2D r = (Rectangle2D) s;
- cairoRectangle(nativePointer, r.getX(), r.getY(), r.getWidth(),
+ Rectangle2D r = (Rectangle2D) s;
+ cairoRectangle(nativePointer, shifted(r.getX(), shiftDrawCalls),
+ shifted(r.getY(), shiftDrawCalls), r.getWidth(),
r.getHeight());
}
- else
- walkPath(s.getPathIterator(null), false);
- double alpha = 1.0;
- if (comp instanceof AlphaComposite)
- alpha = ((AlphaComposite) comp).getAlpha();
- cairoFill(nativePointer, alpha);
+ // We can optimize ellipses too; however we don't bother optimizing arcs:
+ // the iterator is fast enough (an ellipse requires 5 steps using the
+ // iterator, while most arcs are only 2-3)
+ else if (s instanceof Ellipse2D)
+ {
+ Ellipse2D e = (Ellipse2D) s;
+
+ double radius = Math.min(e.getHeight(), e.getWidth()) / 2;
+
+ // Cairo only draws circular shapes, but we can use a stretch to make
+ // them into ellipses
+ double xscale = 1, yscale = 1;
+ if (e.getHeight() != e.getWidth())
+ {
+ cairoSave(nativePointer);
+
+ if (e.getHeight() < e.getWidth())
+ xscale = e.getWidth() / (radius * 2);
+ else
+ yscale = e.getHeight() / (radius * 2);
+
+ if (xscale != 1 || yscale != 1)
+ cairoScale(nativePointer, xscale, yscale);
+ }
+
+ cairoArc(nativePointer,
+ shifted(e.getCenterX() / xscale, shiftDrawCalls),
+ shifted(e.getCenterY() / yscale, shiftDrawCalls), radius, 0,
+ Math.PI * 2);
+
+ if (xscale != 1 || yscale != 1)
+ cairoRestore(nativePointer);
+ }
+
+ // All other shapes are broken down and drawn in steps using the
+ // PathIterator
+ else
+ walkPath(s.getPathIterator(null), shiftDrawCalls);
}
/**
Index: include/gnu_java_awt_peer_gtk_CairoGraphics2D.h
===================================================================
RCS file: /cvsroot/classpath/classpath/include/gnu_java_awt_peer_gtk_CairoGraphics2D.h,v
retrieving revision 1.7
diff -u -r1.7 gnu_java_awt_peer_gtk_CairoGraphics2D.h
--- include/gnu_java_awt_peer_gtk_CairoGraphics2D.h 14 Jun 2006 13:51:04 -0000 1.7
+++ include/gnu_java_awt_peer_gtk_CairoGraphics2D.h 12 Jul 2006 18:18:59 -0000
@@ -16,6 +16,7 @@
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_setGradient (JNIEnv *env, jobject, jlong, jdouble, jdouble, jdouble, jdouble, jint, jint, jint, jint, jint, jint, jint, jint, jboolean);
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_setTexturePixels (JNIEnv *env, jobject, jlong, jintArray, jint, jint, jint);
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoSetMatrix (JNIEnv *env, jobject, jlong, jdoubleArray);
+JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoScale (JNIEnv *env, jobject, jlong, jdouble, jdouble);
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoSetOperator (JNIEnv *env, jobject, jlong, jint);
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoSetRGBAColor (JNIEnv *env, jobject, jlong, jdouble, jdouble, jdouble, jdouble);
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoSetFillRule (JNIEnv *env, jobject, jlong, jint);
@@ -24,6 +25,9 @@
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoDrawGlyphVector (JNIEnv *env, jobject, jlong, jobject, jfloat, jfloat, jint, jintArray, jfloatArray);
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoRelCurveTo (JNIEnv *env, jobject, jlong, jdouble, jdouble, jdouble, jdouble, jdouble, jdouble);
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoRectangle (JNIEnv *env, jobject, jlong, jdouble, jdouble, jdouble, jdouble);
+JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoArc (JNIEnv *env, jobject, jlong, jdouble, jdouble, jdouble, jdouble, jdouble);
+JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoSave (JNIEnv *env, jobject, jlong);
+JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoRestore (JNIEnv *env, jobject, jlong);
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoNewPath (JNIEnv *env, jobject, jlong);
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoClosePath (JNIEnv *env, jobject, jlong);
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoMoveTo (JNIEnv *env, jobject, jlong, jdouble, jdouble);
Index: native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c
===================================================================
RCS file: /cvsroot/classpath/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c,v
retrieving revision 1.11
diff -u -r1.11 gnu_java_awt_peer_gtk_CairoGraphics2D.c
--- native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c 14 Jun 2006 13:51:04 -0000 1.11
+++ native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c 12 Jul 2006 18:19:01 -0000
@@ -263,6 +263,17 @@
}
JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoScale
+(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
+ jlong pointer, jdouble x, jdouble y)
+{
+ struct cairographics2d *gr = JLONG_TO_PTR(struct cairographics2d, pointer);
+ g_assert (gr != NULL);
+
+ cairo_scale (gr->cr, x, y);
+}
+
+JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoDrawGlyphVector
(JNIEnv *env, jobject obj, jlong pointer,
jobject font,
@@ -473,6 +484,28 @@
}
JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoSave
+(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
+ jlong pointer)
+{
+ struct cairographics2d *gr = JLONG_TO_PTR(struct cairographics2d, pointer);
+ g_assert (gr != NULL);
+
+ cairo_save (gr->cr);
+}
+
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoRestore
+(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
+ jlong pointer)
+{
+ struct cairographics2d *gr = JLONG_TO_PTR(struct cairographics2d, pointer);
+ g_assert (gr != NULL);
+
+ cairo_restore (gr->cr);
+}
+
+JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoNewPath
(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
jlong pointer)
@@ -561,6 +594,17 @@
}
JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoArc
+(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
+ jlong pointer, jdouble x, jdouble y, jdouble radius, jdouble angle1,
+ jdouble angle2)
+{
+ struct cairographics2d *gr = JLONG_TO_PTR(struct cairographics2d, pointer);
+
+ cairo_arc (gr->cr, x, y, radius, angle1, angle2);
+}
+
+JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoClosePath
(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
jlong pointer)