1 /* bench.c -- native benchmark for Cairo library (meant to test java2d)
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath examples.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27 #include <sys/timeb.h>
29 G_DEFINE_TYPE (Benchmark, benchmark, GTK_TYPE_DRAWING_AREA);
31 // Needed for the gtk widget, but not used:
33 benchmark_class_init (BenchmarkClass *klass)
38 benchmark_init (Benchmark *obj)
42 // The Arc2D's PathIterator uses some transforms, so we condense the required
43 // functionality of AffineTransform
45 doTransform (double rx, double ry, double theta, double *cvec)
47 // Define identity matrix (corresponds to new AffineTransform())
55 // AffineTransform.scale(rx, ry)
61 // AffineTransform.rotate(theta)
62 double c = cos(theta);
63 double s = sin(theta);
64 double n00 = m00 * c + m01 * s;
65 double n01 = m00 * -s + m01 * c;
66 double n10 = m10 * c + m11 * s;
67 double n11 = m10 * -s + m11 * c;
74 // AffineTransform.transform(cvec, 0, cvec, 0, 1)
76 dstPts[0] = (float) (m00 * cvec[0] + m01 * cvec[1] + m02);
77 dstPts[1] = (float) (m10 * cvec[0] + m11 * cvec[1] + m12);
82 // Place an arc on the cairo path, simulating java2d's Arc2D
84 setupArc(cairo_t *cr, GtkWidget *bench, int shift)
88 // Normally passed into the Arc2D constructor
89 x = bench->allocation.x + (rand() % (bench->allocation.width - minSize + 1));
90 y = bench->allocation.y + (rand() % (bench->allocation.height - minSize + 1));
92 int angle = rand() % 360;
93 int length = (rand() % 360) - angle;
94 int width = rand() % (int)((bench->allocation.width - x - 10) + 10);
95 int height = rand() % (int)((bench->allocation.height - y - 10) + 10);
97 // This is from the ArcPath iterator
98 double start = angle * (M_PI / 180);
99 double extent = length * (M_PI / 180);
104 start = 2 * M_PI - extent + start;
108 if (width < 0 || height < 0) // We assume type == 0; ie, Arc2D.OPEN
110 else if (extent == 0)
112 else if (extent <= M_PI / 2.0)
114 else if (extent <= M_PI)
116 else if (extent <= 3.0 * (M_PI / 2.0))
121 // This is from CairoGraphics2D.walkPath
126 cairo_fill_rule_t cfillrule = CAIRO_FILL_RULE_WINDING;
127 cairo_set_fill_rule(cr, cfillrule);
129 // First iteration will move to the starting point
130 double rx = width / 2;
131 double ry = height / 2;
132 double xmid = x + rx;
133 double ymid = y + ry;
134 coords[0] = xmid + rx * cos(start);
135 coords[1] = ymid - ry * sin(start);
139 xnew = floor(coords[0]) + 0.5;
140 ynew = floor(coords[1]) + 0.5;
148 cairo_move_to(cr, xnew, ynew);
150 // Iterate through segments of the arc
152 for (current = 1; current <= limit; current++)
154 // Back to the ArcPath iterator's getCurrent
155 double kappa = (sqrt(2.0) - 1.0) * (4.0 / 3.0);
156 double quad = (M_PI / 2.0);
158 double curr_begin = start + (current - 1) * quad;
161 if (start + extent - curr_begin < quad)
162 curr_extent = (start + extent) - curr_begin;
166 double portion_of_a_quadrant = curr_extent / quad;
168 double x0 = xmid + rx * cos(curr_begin);
169 double y0 = ymid - ry * sin(curr_begin);
171 double x1 = xmid + rx * cos(curr_begin + curr_extent);
172 double y1 = ymid - ry * sin(curr_begin + curr_extent);
175 double len = kappa * portion_of_a_quadrant;
176 double angle = curr_begin;
180 doTransform(rx, ry, angle, cvec);
181 coords[0] = x0 + cvec[0];
182 coords[1] = y0 - cvec[1];
186 doTransform(rx, ry, angle, cvec);
187 doTransform(1, 1, curr_extent, cvec);
188 coords[2] = x1 + cvec[0];
189 coords[3] = y1 - cvec[1];
194 // draw it, from CairoGraphics2D.walkPath
197 xnew = floor(coords[4]) + 0.5;
198 ynew = floor(coords[5]) + 0.5;
199 cairo_curve_to(cr, floor(coords[0]) + 0.5, floor(coords[1]) + 0.5,
200 floor(coords[2]) + 0.5, floor(coords[3]) + 0.5,
207 cairo_curve_to(cr, coords[0], coords[1], coords[2],
208 coords[3], xnew, ynew);
212 // Randomize the colour, just for asthetics =)
213 cairo_set_source_rgb(cr, (rand() % 100 / (float)100),
214 (rand() % 100 / (float)100),
215 (rand() % 100 / (float)100));
219 // Place a beizer curve on the cairo path, simulating java2d's CubicCurve2D
221 setupCurve(cairo_t *cr, GtkWidget *bench, int shift)
223 // These are options when creating a new curve
224 int x1 = bench->allocation.x + (rand() % (bench->allocation.width - minSize));
225 int y1 = bench->allocation.y + (rand() % (bench->allocation.height - minSize));
226 int xc1 = bench->allocation.x + (rand() % (bench->allocation.width - minSize));
227 int yc1 = bench->allocation.y + (rand() % (bench->allocation.height - minSize));
228 int xc2 = bench->allocation.x + (rand() % (bench->allocation.width - minSize));
229 int yc2 = bench->allocation.y + (rand() % (bench->allocation.height - minSize));
230 int x2 = bench->allocation.x + (rand() % (bench->allocation.width - minSize));
231 int y2 = bench->allocation.y + (rand() % (bench->allocation.height - minSize));
233 // From CairoGraphics2D.walkPath
238 cairo_fill_rule_t cfillrule = CAIRO_FILL_RULE_WINDING;
239 cairo_set_fill_rule(cr, cfillrule);
241 // And into CubicCurve's PathIterator...
242 // start by moving to the starting coordinate
243 coords[0] = (float) x1;
244 coords[1] = (float) y1;
248 xnew = floor(coords[0]) + 0.5;
249 ynew = floor(coords[1]) + 0.5;
257 cairo_move_to(cr, xnew, ynew);
259 // Now the curve itself
260 coords[0] = (float) xc1;
261 coords[1] = (float) yc1;
262 coords[2] = (float) xc2;
263 coords[3] = (float) yc2;
264 coords[4] = (float) x2;
265 coords[5] = (float) y2;
269 xnew = floor(coords[4]) + 0.5;
270 ynew = floor(coords[5]) + 0.5;
271 cairo_curve_to(cr, floor(coords[0]) + 0.5, floor(coords[1]) + 0.5,
272 floor(coords[2]) + 0.5, floor(coords[3]) + 0.5,
279 cairo_curve_to(cr, coords[0], coords[1], coords[2],
280 coords[3], xnew, ynew);
283 // Randomize colour for asthetics
284 cairo_set_source_rgb(cr, (rand() % 100 / (float)100),
285 (rand() % 100 / (float)100),
286 (rand() % 100 / (float)100));
289 // Place a line on the cairo path, simulating java2d's Line2D
291 setupLine(cairo_t *cr, GtkWidget *bench, int shift)
293 // These are set when you create a line
294 int x1 = bench->allocation.x + (rand() % (bench->allocation.width - minSize));
295 int y1 = bench->allocation.y + (rand() % (bench->allocation.height - minSize));
296 int x2 = bench->allocation.x + (rand() % (bench->allocation.width - minSize));
297 int y2 = bench->allocation.y + (rand() % (bench->allocation.height - minSize));
299 // This is from CairoGraphics2D.walkPath
304 cairo_fill_rule_t cfillrule = CAIRO_FILL_RULE_WINDING;
305 cairo_set_fill_rule(cr, cfillrule);
307 // And into Line2D's PathIterator
308 coords[0] = (float) x1;
309 coords[1] = (float) y1;
313 xnew = floor(coords[0]) + 0.5;
314 ynew = floor(coords[1]) + 0.5;
322 cairo_move_to(cr, xnew, ynew);
324 coords[0] = (float) x2;
325 coords[1] = (float) y2;
329 xnew = floor(coords[0]) + 0.5;
330 ynew = floor(coords[1]) + 0.5;
338 cairo_line_to(cr, xnew, ynew);
340 // Randomize colour for asthetics
341 cairo_set_source_rgb(cr, (rand() % 100 / (float)100),
342 (rand() % 100 / (float)100),
343 (rand() % 100 / (float)100));
346 // Place a rectangle on the cairo path, simulating java2d's Rectangle2D
348 setupRect(cairo_t *cr, GtkWidget *bench, int shift)
350 // These are set when you create a rectangle
351 int x1 = bench->allocation.x + (rand() % (bench->allocation.width - minSize));
352 int y1 = bench->allocation.y + (rand() % (bench->allocation.height - minSize));
353 int x2 = bench->allocation.x + (rand() % (bench->allocation.width - minSize));
354 int y2 = bench->allocation.y + (rand() % (bench->allocation.height - minSize));
356 // draw() and fill() have been optimized to ignore the PathIterator.
357 // We do the same here.
363 xnew = floor(x1) + 0.5;
364 ynew = floor(y1) + 0.5;
372 cairo_rectangle(cr, x1, y1, x2, y2);
374 // Randomize colour for asthetics
375 cairo_set_source_rgb(cr, (rand() % 100 / (float)100),
376 (rand() % 100 / (float)100),
377 (rand() % 100 / (float)100));
380 // The real work gets done here: this function is called when the widget
381 // is drawn on screen.
383 draw (GtkWidget *bench, cairo_t *cr)
389 cairo_set_line_width(cr, lineWidth);
392 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
394 cairo_set_antialias(cr, CAIRO_ANTIALIAS_GRAY);
396 // Tell the user what's going on
397 printf("Testing native cairo drawing..\n");
398 printf(" Screen size is %d x %d \n", screenWidth, screenHeight);
399 printf(" Line width is %d\n", lineWidth);
400 printf(" Test size: %d\n", testSize);
403 printf(" Anti-alias is off\n");
405 printf(" Anti-alias is on\n");
415 for (i = 0; i < testSize; i++)
417 setupArc(cr, bench, 1);
422 timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
423 printf("Draw arc: %d ms\n", timeElapsed);
428 for (i = 0; i < testSize; i++)
430 setupArc(cr, bench, 0);
435 timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
436 printf("Fill arc: %d ms\n", timeElapsed);
443 for (i = 0; i < testSize; i++)
445 setupCurve(cr, bench, 1);
450 timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
451 printf("Draw cubic curve: %d ms\n", timeElapsed);
454 // Ellipse: skip; this is just a special case of arc
455 // General path: skip; this doesn't even work in java2d
461 for (i = 0; i < testSize; i++)
463 setupLine(cr, bench, 1);
468 timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
469 printf("Draw line: %d ms\n", timeElapsed);
472 // Draw & fill Rectangle
477 for (i = 0; i < testSize; i++)
479 setupRect(cr, bench, 1);
484 timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
485 printf("Draw rectangle: %d ms\n", timeElapsed);
489 for (i = 0; i < testSize; i++)
491 setupRect(cr, bench, 0);
496 timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
497 printf("Fill rectangle: %d ms\n", timeElapsed);
500 // Round rectangle: skip, it's just a combination of lines and curves
509 return g_object_new (BENCHMARK_TYPE, NULL);
513 main (int argc, char **argv)
527 // Process any command-line user options
529 for (i = 1; i < argc; i++)
531 // Process options first
532 if (!strcmp(argv[i], "-a"))
534 else if (!strcmp(argv[i], "-h"))
535 screenHeight = atoi(argv[++i]);
536 else if (!strcmp(argv[i], "-l"))
537 lineWidth = atoi(argv[++i]);
538 else if (!strcmp(argv[i], "-t"))
539 testSize = atoi(argv[++i]);
540 else if (!strcmp(argv[i], "-w"))
541 screenWidth = atoi(argv[++i]);
542 else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--h")
543 || !strcmp(argv[i], "-help") || !strcmp(argv[i], "--help"))
545 printf("Cairo benchmarker, meant to measure JNI overhead\n");
546 printf("Usage: bench [-a] [-h height] [-t test size] [-w width] [tests...]\n");
548 printf(" Valid options: -a turn on anti-aliasing (default off)\n");
549 printf(" -h set screen height (default 240)\n");
550 printf(" -l set stroke line width (default 1)\n");
551 printf(" -t set test size (default 1000)\n");
552 printf(" -w set screen width (default 320)\n");
553 printf(" -h | --help\n");
554 printf(" Valid tests: arc\n");
558 printf(" (default: run all)\n");
563 else if (!strcmp(argv[i], "arc"))
565 else if (!strcmp(argv[i], "curve"))
567 else if (!strcmp(argv[i], "line"))
569 else if (!strcmp(argv[i], "rect"))
573 // If no tests were specified, we default to running all of them
574 if (arcTest == 0 && curveTest == 0 && lineTest == 0 && rectTest == 0)
583 GtkWidget *window, *bench;
584 gtk_init (&argc, &argv);
586 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
587 gtk_window_resize(GTK_WINDOW(window), screenWidth, screenHeight);
588 gtk_window_set_title(GTK_WINDOW(window), "cairo benchmark");
590 // Set up benchmkar and cairo surface
591 bench = benchmark_new ();
592 gtk_container_add (GTK_CONTAINER (window), bench);
593 gtk_widget_show_all (window);
596 cr = gdk_cairo_create (bench->window);
601 // Hold output on screen until user exits.
602 printf("Press any key to exit.\n");