OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / lib / classpath / examples / gnu / classpath / examples / java2d / bench.c
1 /* bench.c -- native benchmark for Cairo library (meant to test java2d)
2    Copyright (C) 2006  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath examples.
5
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)
9 any later version.
10
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.
15
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
19 02110-1301 USA. */
20
21 #include "bench.h"
22 #include <math.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <gtk/gtk.h>
27 #include <sys/timeb.h>
28
29 G_DEFINE_TYPE (Benchmark, benchmark, GTK_TYPE_DRAWING_AREA);
30
31 // Needed for the gtk widget, but not used:
32 static void
33 benchmark_class_init (BenchmarkClass *klass)
34 {
35 }
36
37 static void
38 benchmark_init (Benchmark *obj)
39 {
40 }
41
42 // The Arc2D's PathIterator uses some transforms, so we condense the required
43 // functionality of AffineTransform
44 static void
45 doTransform (double rx, double ry, double theta, double *cvec)
46 {
47   // Define identity matrix (corresponds to new AffineTransform())
48   double m00 = 1;
49   double m10 = 0;
50   double m01 = 0;
51   double m11 = 1;
52   double m02 = 0;
53   double m12 = 0;
54
55   // AffineTransform.scale(rx, ry)
56   m00 = m00 * rx;
57   m01 = m01 * ry;
58   m10 = m10 * rx;
59   m11 = m11 * ry;
60
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;
68
69   m00 = n00;
70   m01 = n01;
71   m10 = n10;
72   m11 = n11;    
73     
74   // AffineTransform.transform(cvec, 0, cvec, 0, 1)
75   double dstPts[2];
76   dstPts[0] = (float) (m00 * cvec[0] + m01 * cvec[1] + m02);
77   dstPts[1] = (float) (m10 * cvec[0] + m11 * cvec[1] + m12);
78   cvec[0] = dstPts[0];
79   cvec[1] = dstPts[1];
80 }
81
82 // Place an arc on the cairo path, simulating java2d's Arc2D
83 static void 
84 setupArc(cairo_t *cr, GtkWidget *bench, int shift)
85 {
86   double x, y;
87   
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));
91   
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);
96   
97   // This is from the ArcPath iterator
98   double start = angle * (M_PI / 180);
99   double extent = length * (M_PI / 180);
100
101   if (extent < 0)
102     {
103       extent = -extent;
104       start = 2 * M_PI - extent + start;
105     }
106
107   int limit;
108   if (width < 0 || height < 0)  // We assume type == 0; ie, Arc2D.OPEN
109     limit = -1;
110   else if (extent == 0)
111     limit = 0;
112   else if (extent <= M_PI / 2.0)
113     limit = 1;
114   else if (extent <= M_PI)
115     limit = 2;
116   else if (extent <= 3.0 * (M_PI / 2.0))
117     limit = 3;
118   else
119     limit = 4;
120     
121   // This is from CairoGraphics2D.walkPath
122   double xnew = 0;
123   double ynew = 0;
124   double coords[6];
125
126   cairo_fill_rule_t cfillrule = CAIRO_FILL_RULE_WINDING;
127   cairo_set_fill_rule(cr, cfillrule);
128   
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);
136   
137   if (shift == 1)
138     {
139       xnew = floor(coords[0]) + 0.5;
140       ynew = floor(coords[1]) + 0.5;
141     }
142   else
143     {
144       xnew = coords[0];
145       ynew = coords[1];
146     }
147     
148   cairo_move_to(cr, xnew, ynew);
149
150   // Iterate through segments of the arc  
151   int current;
152   for (current = 1; current <= limit; current++)
153     {
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);
157
158       double curr_begin = start + (current - 1) * quad;
159       double curr_extent;
160       
161       if (start + extent - curr_begin < quad)
162         curr_extent = (start + extent) - curr_begin;
163       else
164         curr_extent = quad;
165     
166       double portion_of_a_quadrant = curr_extent / quad;
167
168       double x0 = xmid + rx * cos(curr_begin);
169       double y0 = ymid - ry * sin(curr_begin);
170
171       double x1 = xmid + rx * cos(curr_begin + curr_extent);
172       double y1 = ymid - ry * sin(curr_begin + curr_extent);
173
174       double cvec[2];
175       double len = kappa * portion_of_a_quadrant;
176       double angle = curr_begin;
177
178       cvec[0] = 0;
179       cvec[1] = len;
180       doTransform(rx, ry, angle, cvec);
181       coords[0] = x0 + cvec[0];
182       coords[1] = y0 - cvec[1];
183
184       cvec[0] = 0;
185       cvec[1] = -len;
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];
190
191       coords[4] = x1;
192       coords[5] = y1;
193     
194       // draw it, from CairoGraphics2D.walkPath
195       if (shift == 1)
196         {
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,
201                          xnew, ynew);
202         }
203       else
204         {
205           xnew = coords[4];
206           ynew = coords[5];
207           cairo_curve_to(cr, coords[0], coords[1], coords[2],
208                          coords[3], xnew, ynew);
209         }
210     }
211   
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));
216   
217 }
218
219 // Place a beizer curve on the cairo path, simulating java2d's CubicCurve2D
220 static void 
221 setupCurve(cairo_t *cr, GtkWidget *bench, int shift)
222 {
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));
232   
233   // From CairoGraphics2D.walkPath
234   double xnew = 0;
235   double ynew = 0;
236   double coords[6];
237
238   cairo_fill_rule_t cfillrule = CAIRO_FILL_RULE_WINDING;
239   cairo_set_fill_rule(cr, cfillrule);
240   
241   // And into CubicCurve's PathIterator...
242   // start by moving to the starting coordinate
243   coords[0] = (float) x1;
244   coords[1] = (float) y1;
245   
246   if (shift == 1)
247     {
248       xnew = floor(coords[0]) + 0.5;
249       ynew = floor(coords[1]) + 0.5;
250     }
251   else
252     {
253       xnew = coords[0];
254       ynew = coords[1];
255     }
256     
257   cairo_move_to(cr, xnew, ynew);
258   
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;
266   
267   if (shift == 1)
268     {
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,
273                      xnew, ynew);
274     }
275   else
276     {
277       xnew = coords[4];
278       ynew = coords[5];
279       cairo_curve_to(cr, coords[0], coords[1], coords[2], 
280                      coords[3], xnew, ynew);
281     }
282   
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));
287 }
288
289 // Place a line on the cairo path, simulating java2d's Line2D
290 static void 
291 setupLine(cairo_t *cr, GtkWidget *bench, int shift)
292 {
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));
298   
299   // This is from CairoGraphics2D.walkPath
300   double xnew = 0;
301   double ynew = 0;
302   double coords[6];
303
304   cairo_fill_rule_t cfillrule = CAIRO_FILL_RULE_WINDING;
305   cairo_set_fill_rule(cr, cfillrule);
306   
307   // And into Line2D's PathIterator
308   coords[0] = (float) x1;
309   coords[1] = (float) y1;
310   
311   if (shift == 1)
312     {
313       xnew = floor(coords[0]) + 0.5;
314       ynew = floor(coords[1]) + 0.5;
315     }
316   else
317     {
318       xnew = coords[0];
319       ynew = coords[1];
320     }
321     
322   cairo_move_to(cr, xnew, ynew);
323   
324   coords[0] = (float) x2;
325   coords[1] = (float) y2;
326   
327   if (shift == 1)
328     {
329       xnew = floor(coords[0]) + 0.5;
330       ynew = floor(coords[1]) + 0.5;
331     }
332   else
333     {
334       xnew = coords[0];
335       ynew = coords[1];
336     }
337     
338   cairo_line_to(cr, xnew, ynew);
339   
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));
344 }
345
346 // Place a rectangle on the cairo path, simulating java2d's Rectangle2D
347 static void 
348 setupRect(cairo_t *cr, GtkWidget *bench, int shift)
349 {
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));
355   
356   // draw() and fill() have been optimized to ignore the PathIterator.
357   // We do the same here.
358   double xnew = 0;
359   double ynew = 0;
360   
361   if (shift == 1)
362     {
363       xnew = floor(x1) + 0.5;
364       ynew = floor(y1) + 0.5;
365     }
366   else
367     {
368       xnew = x1;
369       ynew = y1;
370     }
371     
372   cairo_rectangle(cr, x1, y1, x2, y2);
373     
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));
378 }
379
380 // The real work gets done here: this function is called when the widget
381 // is drawn on screen.
382 static void
383 draw (GtkWidget *bench, cairo_t *cr)
384 {
385   // Setup
386   struct timeb t1, t2;
387   int i, timeElapsed;
388
389   cairo_set_line_width(cr, lineWidth);
390   
391   if (antialias == 0)
392     cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
393   else
394     cairo_set_antialias(cr, CAIRO_ANTIALIAS_GRAY);
395   
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);
401   
402   if (antialias == 0)
403     printf("  Anti-alias is off\n");
404   else
405     printf("  Anti-alias is on\n");
406     
407   printf("\n");
408   fflush(stdout);
409
410   // Draw & fill Arc
411   if (arcTest == 1)
412     {
413       // Draw
414       ftime(&t1);
415       for (i = 0; i < testSize; i++)
416         {
417           setupArc(cr, bench, 1);
418           cairo_stroke (cr);
419         }
420         
421       ftime(&t2);
422       timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
423       printf("Draw arc: %d ms\n", timeElapsed);
424       fflush(stdout);
425
426       // Fill
427       ftime(&t1);
428       for (i = 0; i < testSize; i++)
429         {
430           setupArc(cr, bench, 0);
431           cairo_fill (cr);
432         }
433         
434       ftime(&t2);
435       timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
436       printf("Fill arc: %d ms\n", timeElapsed);
437     }
438
439   // Draw cubic curve
440   if (curveTest == 1)
441     {
442       ftime(&t1);
443       for (i = 0; i < testSize; i++)
444         {
445           setupCurve(cr, bench, 1);
446           cairo_stroke (cr);
447         }
448         
449       ftime(&t2);
450       timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
451       printf("Draw cubic curve: %d ms\n", timeElapsed);
452     }
453   
454   // Ellipse: skip; this is just a special case of arc
455   // General path: skip; this doesn't even work in java2d
456
457   // Draw Line
458   if (lineTest == 1)
459     {
460       ftime(&t1);
461       for (i = 0; i < testSize; i++)
462         {
463           setupLine(cr, bench, 1);
464           cairo_stroke (cr);
465         }
466         
467       ftime(&t2);
468       timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
469       printf("Draw line: %d ms\n", timeElapsed);
470     }
471   
472   // Draw & fill Rectangle
473   if (rectTest == 1)
474     {
475       // Draw
476       ftime(&t1);
477       for (i = 0; i < testSize; i++)
478         {
479           setupRect(cr, bench, 1);
480           cairo_stroke (cr);
481         }
482         
483       ftime(&t2);
484       timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
485       printf("Draw rectangle: %d ms\n", timeElapsed);
486     
487       // Fill
488       ftime(&t1);
489       for (i = 0; i < testSize; i++)
490         {
491           setupRect(cr, bench, 0);
492           cairo_fill (cr);
493         }
494         
495       ftime(&t2);
496       timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
497       printf("Fill rectangle: %d ms\n", timeElapsed);
498     }
499   
500   // Round rectangle: skip, it's just a combination of lines and curves
501   // Image: skip?
502   
503   printf("\n");
504 }
505
506 GtkWidget *
507 benchmark_new (void)
508 {
509   return g_object_new (BENCHMARK_TYPE, NULL);
510 }
511
512 int
513 main (int argc, char **argv)
514 {
515   // Set defaults
516   minSize = 10;
517   arcTest = 0;
518   curveTest = 0;
519   lineTest = 0;
520   rectTest = 0;
521   screenWidth = 320;
522   screenHeight = 240;
523   testSize = 1000;
524   antialias = 0;
525   lineWidth = 1;
526   
527   // Process any command-line user options
528   int i;
529   for (i = 1; i < argc; i++)
530     {
531       // Process options first
532       if (!strcmp(argv[i], "-a"))
533         antialias = 1;
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"))
544         {
545           printf("Cairo benchmarker, meant to measure JNI overhead\n");
546           printf("Usage: bench [-a] [-h height] [-t test size] [-w width] [tests...]\n");
547           printf("\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");
555           printf("               curve\n");
556           printf("               line\n");
557           printf("               rect\n");
558           printf("               (default: run all)\n");
559           exit (0);
560         }
561
562       // Process tests
563       else if (!strcmp(argv[i], "arc"))
564         arcTest = 1;
565       else if (!strcmp(argv[i], "curve"))
566         curveTest = 1;
567       else if (!strcmp(argv[i], "line"))
568         lineTest = 1;
569       else if (!strcmp(argv[i], "rect"))
570         rectTest = 1;
571     }
572   
573   // If no tests were specified, we default to running all of them
574   if (arcTest == 0 && curveTest == 0 && lineTest == 0 && rectTest == 0)
575     {
576       arcTest = 1;
577       curveTest = 1;
578       lineTest = 1;
579       rectTest = 1;
580     }
581   
582   // Set up gtk widget
583   GtkWidget *window, *bench;
584   gtk_init (&argc, &argv);
585
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");
589   
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);
594   
595   cairo_t *cr;
596   cr = gdk_cairo_create (bench->window);
597
598   // Run tests
599   draw (bench, cr);
600
601   // Hold output on screen until user exits.
602   printf("Press any key to exit.\n");
603   getchar();
604   exit(0);
605 gtk_main();
606 }