OSDN Git Service

2006-08-14 Mark Wielaard <mark@klomp.org>
[pf3gnuchains/gcc-fork.git] / libjava / classpath / examples / gnu / classpath / examples / java2d / bench.c
diff --git a/libjava/classpath/examples/gnu/classpath/examples/java2d/bench.c b/libjava/classpath/examples/gnu/classpath/examples/java2d/bench.c
new file mode 100644 (file)
index 0000000..e5b45aa
--- /dev/null
@@ -0,0 +1,606 @@
+/* bench.c -- native benchmark for Cairo library (meant to test java2d)
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath examples.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA. */
+
+#include "bench.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <sys/timeb.h>
+
+G_DEFINE_TYPE (Benchmark, benchmark, GTK_TYPE_DRAWING_AREA);
+
+// Needed for the gtk widget, but not used:
+static void
+benchmark_class_init (BenchmarkClass *klass)
+{
+}
+
+static void
+benchmark_init (Benchmark *obj)
+{
+}
+
+// The Arc2D's PathIterator uses some transforms, so we condense the required
+// functionality of AffineTransform
+static void
+doTransform (double rx, double ry, double theta, double *cvec)
+{
+  // Define identity matrix (corresponds to new AffineTransform())
+  double m00 = 1;
+  double m10 = 0;
+  double m01 = 0;
+  double m11 = 1;
+  double m02 = 0;
+  double m12 = 0;
+
+  // AffineTransform.scale(rx, ry)
+  m00 = m00 * rx;
+  m01 = m01 * ry;
+  m10 = m10 * rx;
+  m11 = m11 * ry;
+
+  // AffineTransform.rotate(theta)
+  double c = cos(theta);
+  double s = sin(theta);
+  double n00 = m00 *  c + m01 * s;
+  double n01 = m00 * -s + m01 * c;
+  double n10 = m10 *  c + m11 * s;
+  double n11 = m10 * -s + m11 * c;
+
+  m00 = n00;
+  m01 = n01;
+  m10 = n10;
+  m11 = n11;    
+    
+  // AffineTransform.transform(cvec, 0, cvec, 0, 1)
+  double dstPts[2];
+  dstPts[0] = (float) (m00 * cvec[0] + m01 * cvec[1] + m02);
+  dstPts[1] = (float) (m10 * cvec[0] + m11 * cvec[1] + m12);
+  cvec[0] = dstPts[0];
+  cvec[1] = dstPts[1];
+}
+
+// Place an arc on the cairo path, simulating java2d's Arc2D
+static void 
+setupArc(cairo_t *cr, GtkWidget *bench, int shift)
+{
+  double x, y;
+  
+  // Normally passed into the Arc2D constructor
+  x = bench->allocation.x + (rand() % (bench->allocation.width - minSize + 1));
+  y = bench->allocation.y + (rand() % (bench->allocation.height - minSize + 1));
+  
+  int angle = rand() % 360;
+  int length = (rand() % 360) - angle;
+  int width = rand() % (int)((bench->allocation.width - x - 10) + 10);
+  int height = rand() % (int)((bench->allocation.height - y - 10) + 10);
+  
+  // This is from the ArcPath iterator
+  double start = angle * (M_PI / 180);
+  double extent = length * (M_PI / 180);
+
+  if (extent < 0)
+    {
+      extent = -extent;
+      start = 2 * M_PI - extent + start;
+    }
+
+  int limit;
+  if (width < 0 || height < 0)  // We assume type == 0; ie, Arc2D.OPEN
+    limit = -1;
+  else if (extent == 0)
+    limit = 0;
+  else if (extent <= M_PI / 2.0)
+    limit = 1;
+  else if (extent <= M_PI)
+    limit = 2;
+  else if (extent <= 3.0 * (M_PI / 2.0))
+    limit = 3;
+  else
+    limit = 4;
+    
+  // This is from CairoGraphics2D.walkPath
+  double xnew = 0;
+  double ynew = 0;
+  double coords[6];
+
+  cairo_fill_rule_t cfillrule = CAIRO_FILL_RULE_WINDING;
+  cairo_set_fill_rule(cr, cfillrule);
+  
+  // First iteration will move to the starting point
+  double rx = width / 2;
+  double ry = height / 2;
+  double xmid = x + rx;
+  double ymid = y + ry;
+  coords[0] = xmid + rx * cos(start);
+  coords[1] = ymid - ry * sin(start);
+  
+  if (shift == 1)
+    {
+      xnew = floor(coords[0]) + 0.5;
+      ynew = floor(coords[1]) + 0.5;
+    }
+  else
+    {
+      xnew = coords[0];
+      ynew = coords[1];
+    }
+    
+  cairo_move_to(cr, xnew, ynew);
+
+  // Iterate through segments of the arc  
+  int current;
+  for (current = 1; current <= limit; current++)
+    {
+      // Back to the ArcPath iterator's getCurrent
+      double kappa = (sqrt(2.0) - 1.0) * (4.0 / 3.0);
+      double quad = (M_PI / 2.0);
+
+      double curr_begin = start + (current - 1) * quad;
+      double curr_extent;
+      
+      if (start + extent - curr_begin < quad)
+        curr_extent = (start + extent) - curr_begin;
+      else
+        curr_extent = quad;
+    
+      double portion_of_a_quadrant = curr_extent / quad;
+
+      double x0 = xmid + rx * cos(curr_begin);
+      double y0 = ymid - ry * sin(curr_begin);
+
+      double x1 = xmid + rx * cos(curr_begin + curr_extent);
+      double y1 = ymid - ry * sin(curr_begin + curr_extent);
+
+      double cvec[2];
+      double len = kappa * portion_of_a_quadrant;
+      double angle = curr_begin;
+
+      cvec[0] = 0;
+      cvec[1] = len;
+      doTransform(rx, ry, angle, cvec);
+      coords[0] = x0 + cvec[0];
+      coords[1] = y0 - cvec[1];
+
+      cvec[0] = 0;
+      cvec[1] = -len;
+      doTransform(rx, ry, angle, cvec);
+      doTransform(1, 1, curr_extent, cvec);
+      coords[2] = x1 + cvec[0];
+      coords[3] = y1 - cvec[1];
+
+      coords[4] = x1;
+      coords[5] = y1;
+    
+      // draw it, from CairoGraphics2D.walkPath
+      if (shift == 1)
+        {
+          xnew = floor(coords[4]) + 0.5;
+          ynew = floor(coords[5]) + 0.5;
+          cairo_curve_to(cr, floor(coords[0]) + 0.5, floor(coords[1]) + 0.5,
+                         floor(coords[2]) + 0.5, floor(coords[3]) + 0.5,
+                         xnew, ynew);
+        }
+      else
+        {
+          xnew = coords[4];
+          ynew = coords[5];
+          cairo_curve_to(cr, coords[0], coords[1], coords[2],
+                         coords[3], xnew, ynew);
+        }
+    }
+  
+  // Randomize the colour, just for asthetics =)
+  cairo_set_source_rgb(cr, (rand() % 100 / (float)100),
+                       (rand() % 100 / (float)100),
+                       (rand() % 100 / (float)100));
+  
+}
+
+// Place a beizer curve on the cairo path, simulating java2d's CubicCurve2D
+static void 
+setupCurve(cairo_t *cr, GtkWidget *bench, int shift)
+{
+  // These are options when creating a new curve
+  int x1 = bench->allocation.x + (rand() % (bench->allocation.width - minSize));
+  int y1 = bench->allocation.y + (rand() % (bench->allocation.height - minSize));
+  int xc1 = bench->allocation.x + (rand() % (bench->allocation.width - minSize));
+  int yc1 = bench->allocation.y + (rand() % (bench->allocation.height - minSize));
+  int xc2 = bench->allocation.x + (rand() % (bench->allocation.width - minSize));
+  int yc2 = bench->allocation.y + (rand() % (bench->allocation.height - minSize));
+  int x2 = bench->allocation.x + (rand() % (bench->allocation.width - minSize));
+  int y2 = bench->allocation.y + (rand() % (bench->allocation.height - minSize));
+  
+  // From CairoGraphics2D.walkPath
+  double xnew = 0;
+  double ynew = 0;
+  double coords[6];
+
+  cairo_fill_rule_t cfillrule = CAIRO_FILL_RULE_WINDING;
+  cairo_set_fill_rule(cr, cfillrule);
+  
+  // And into CubicCurve's PathIterator...
+  // start by moving to the starting coordinate
+  coords[0] = (float) x1;
+  coords[1] = (float) y1;
+  
+  if (shift == 1)
+    {
+      xnew = floor(coords[0]) + 0.5;
+      ynew = floor(coords[1]) + 0.5;
+    }
+  else
+    {
+      xnew = coords[0];
+      ynew = coords[1];
+    }
+    
+  cairo_move_to(cr, xnew, ynew);
+  
+  // Now the curve itself
+  coords[0] = (float) xc1;
+  coords[1] = (float) yc1;
+  coords[2] = (float) xc2;
+  coords[3] = (float) yc2;
+  coords[4] = (float) x2;
+  coords[5] = (float) y2;
+  
+  if (shift == 1)
+    {
+      xnew = floor(coords[4]) + 0.5;
+      ynew = floor(coords[5]) + 0.5;
+      cairo_curve_to(cr, floor(coords[0]) + 0.5, floor(coords[1]) + 0.5,
+                     floor(coords[2]) + 0.5, floor(coords[3]) + 0.5,
+                     xnew, ynew);
+    }
+  else
+    {
+      xnew = coords[4];
+      ynew = coords[5];
+      cairo_curve_to(cr, coords[0], coords[1], coords[2], 
+                     coords[3], xnew, ynew);
+    }
+  
+  // Randomize colour for asthetics
+  cairo_set_source_rgb(cr, (rand() % 100 / (float)100),
+                       (rand() % 100 / (float)100),
+                       (rand() % 100 / (float)100));
+}
+
+// Place a line on the cairo path, simulating java2d's Line2D
+static void 
+setupLine(cairo_t *cr, GtkWidget *bench, int shift)
+{
+  // These are set when you create a line
+  int x1 = bench->allocation.x + (rand() % (bench->allocation.width - minSize));
+  int y1 = bench->allocation.y + (rand() % (bench->allocation.height - minSize));
+  int x2 = bench->allocation.x + (rand() % (bench->allocation.width - minSize));
+  int y2 = bench->allocation.y + (rand() % (bench->allocation.height - minSize));
+  
+  // This is from CairoGraphics2D.walkPath
+  double xnew = 0;
+  double ynew = 0;
+  double coords[6];
+
+  cairo_fill_rule_t cfillrule = CAIRO_FILL_RULE_WINDING;
+  cairo_set_fill_rule(cr, cfillrule);
+  
+  // And into Line2D's PathIterator
+  coords[0] = (float) x1;
+  coords[1] = (float) y1;
+  
+  if (shift == 1)
+    {
+      xnew = floor(coords[0]) + 0.5;
+      ynew = floor(coords[1]) + 0.5;
+    }
+  else
+    {
+      xnew = coords[0];
+      ynew = coords[1];
+    }
+    
+  cairo_move_to(cr, xnew, ynew);
+  
+  coords[0] = (float) x2;
+  coords[1] = (float) y2;
+  
+  if (shift == 1)
+    {
+      xnew = floor(coords[0]) + 0.5;
+      ynew = floor(coords[1]) + 0.5;
+    }
+  else
+    {
+      xnew = coords[0];
+      ynew = coords[1];
+    }
+    
+  cairo_line_to(cr, xnew, ynew);
+  
+  // Randomize colour for asthetics
+  cairo_set_source_rgb(cr, (rand() % 100 / (float)100),
+                       (rand() % 100 / (float)100),
+                       (rand() % 100 / (float)100));
+}
+
+// Place a rectangle on the cairo path, simulating java2d's Rectangle2D
+static void 
+setupRect(cairo_t *cr, GtkWidget *bench, int shift)
+{
+  // These are set when you create a rectangle
+  int x1 = bench->allocation.x + (rand() % (bench->allocation.width - minSize));
+  int y1 = bench->allocation.y + (rand() % (bench->allocation.height - minSize));
+  int x2 = bench->allocation.x + (rand() % (bench->allocation.width - minSize));
+  int y2 = bench->allocation.y + (rand() % (bench->allocation.height - minSize));
+  
+  // draw() and fill() have been optimized to ignore the PathIterator.
+  // We do the same here.
+  double xnew = 0;
+  double ynew = 0;
+  
+  if (shift == 1)
+    {
+      xnew = floor(x1) + 0.5;
+      ynew = floor(y1) + 0.5;
+    }
+  else
+    {
+      xnew = x1;
+      ynew = y1;
+    }
+    
+  cairo_rectangle(cr, x1, y1, x2, y2);
+    
+  // Randomize colour for asthetics
+  cairo_set_source_rgb(cr, (rand() % 100 / (float)100),
+                       (rand() % 100 / (float)100),
+                       (rand() % 100 / (float)100));
+}
+
+// The real work gets done here: this function is called when the widget
+// is drawn on screen.
+static void
+draw (GtkWidget *bench, cairo_t *cr)
+{
+  // Setup
+  struct timeb t1, t2;
+  int i, timeElapsed;
+
+  cairo_set_line_width(cr, lineWidth);
+  
+  if (antialias == 0)
+    cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
+  else
+    cairo_set_antialias(cr, CAIRO_ANTIALIAS_GRAY);
+  
+  // Tell the user what's going on
+  printf("Testing native cairo drawing..\n");
+  printf("  Screen size is %d x %d \n", screenWidth, screenHeight);
+  printf("  Line width is %d\n", lineWidth);
+  printf("  Test size: %d\n", testSize);
+  
+  if (antialias == 0)
+    printf("  Anti-alias is off\n");
+  else
+    printf("  Anti-alias is on\n");
+    
+  printf("\n");
+  fflush(stdout);
+
+  // Draw & fill Arc
+  if (arcTest == 1)
+    {
+      // Draw
+      ftime(&t1);
+      for (i = 0; i < testSize; i++)
+        {
+          setupArc(cr, bench, 1);
+          cairo_stroke (cr);
+        }
+        
+      ftime(&t2);
+      timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
+      printf("Draw arc: %d ms\n", timeElapsed);
+      fflush(stdout);
+
+      // Fill
+      ftime(&t1);
+      for (i = 0; i < testSize; i++)
+        {
+          setupArc(cr, bench, 0);
+          cairo_fill (cr);
+        }
+        
+      ftime(&t2);
+      timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
+      printf("Fill arc: %d ms\n", timeElapsed);
+    }
+
+  // Draw cubic curve
+  if (curveTest == 1)
+    {
+      ftime(&t1);
+      for (i = 0; i < testSize; i++)
+        {
+          setupCurve(cr, bench, 1);
+          cairo_stroke (cr);
+        }
+        
+      ftime(&t2);
+      timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
+      printf("Draw cubic curve: %d ms\n", timeElapsed);
+    }
+  
+  // Ellipse: skip; this is just a special case of arc
+  // General path: skip; this doesn't even work in java2d
+
+  // Draw Line
+  if (lineTest == 1)
+    {
+      ftime(&t1);
+      for (i = 0; i < testSize; i++)
+        {
+          setupLine(cr, bench, 1);
+          cairo_stroke (cr);
+        }
+        
+      ftime(&t2);
+      timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
+      printf("Draw line: %d ms\n", timeElapsed);
+    }
+  
+  // Draw & fill Rectangle
+  if (rectTest == 1)
+    {
+      // Draw
+      ftime(&t1);
+      for (i = 0; i < testSize; i++)
+        {
+          setupRect(cr, bench, 1);
+          cairo_stroke (cr);
+        }
+        
+      ftime(&t2);
+      timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
+      printf("Draw rectangle: %d ms\n", timeElapsed);
+    
+      // Fill
+      ftime(&t1);
+      for (i = 0; i < testSize; i++)
+        {
+          setupRect(cr, bench, 0);
+          cairo_fill (cr);
+        }
+        
+      ftime(&t2);
+      timeElapsed = 1000 * (t2.time - t1.time) + (t2.millitm - t1.millitm);
+      printf("Fill rectangle: %d ms\n", timeElapsed);
+    }
+  
+  // Round rectangle: skip, it's just a combination of lines and curves
+  // Image: skip?
+  
+  printf("\n");
+}
+
+GtkWidget *
+benchmark_new (void)
+{
+  return g_object_new (BENCHMARK_TYPE, NULL);
+}
+
+int
+main (int argc, char **argv)
+{
+  // Set defaults
+  minSize = 10;
+  arcTest = 0;
+  curveTest = 0;
+  lineTest = 0;
+  rectTest = 0;
+  screenWidth = 320;
+  screenHeight = 240;
+  testSize = 1000;
+  antialias = 0;
+  lineWidth = 1;
+  
+  // Process any command-line user options
+  int i;
+  for (i = 1; i < argc; i++)
+    {
+      // Process options first
+      if (!strcmp(argv[i], "-a"))
+        antialias = 1;
+      else if (!strcmp(argv[i], "-h"))
+        screenHeight = atoi(argv[++i]);
+      else if (!strcmp(argv[i], "-l"))
+        lineWidth = atoi(argv[++i]);
+      else if (!strcmp(argv[i], "-t"))
+        testSize = atoi(argv[++i]);
+      else if (!strcmp(argv[i], "-w"))
+        screenWidth = atoi(argv[++i]);
+      else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--h")
+               || !strcmp(argv[i], "-help") || !strcmp(argv[i], "--help"))
+        {
+          printf("Cairo benchmarker, meant to measure JNI overhead\n");
+          printf("Usage: bench [-a] [-h height] [-t test size] [-w width] [tests...]\n");
+          printf("\n");
+          printf("  Valid options: -a   turn on anti-aliasing (default off)\n");
+          printf("                 -h   set screen height (default 240)\n");
+          printf("                 -l   set stroke line width (default 1)\n");
+          printf("                 -t   set test size (default 1000)\n");
+          printf("                 -w   set screen width (default 320)\n");
+          printf("                 -h | --help\n");
+          printf("  Valid tests: arc\n");
+          printf("               curve\n");
+          printf("               line\n");
+          printf("               rect\n");
+          printf("               (default: run all)\n");
+          exit (0);
+        }
+
+      // Process tests
+      else if (!strcmp(argv[i], "arc"))
+        arcTest = 1;
+      else if (!strcmp(argv[i], "curve"))
+        curveTest = 1;
+      else if (!strcmp(argv[i], "line"))
+        lineTest = 1;
+      else if (!strcmp(argv[i], "rect"))
+        rectTest = 1;
+    }
+  
+  // If no tests were specified, we default to running all of them
+  if (arcTest == 0 && curveTest == 0 && lineTest == 0 && rectTest == 0)
+    {
+      arcTest = 1;
+      curveTest = 1;
+      lineTest = 1;
+      rectTest = 1;
+    }
+  
+  // Set up gtk widget
+  GtkWidget *window, *bench;
+  gtk_init (&argc, &argv);
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_resize(GTK_WINDOW(window), screenWidth, screenHeight);
+  gtk_window_set_title(GTK_WINDOW(window), "cairo benchmark");
+  
+  // Set up benchmkar and cairo surface
+  bench = benchmark_new ();
+  gtk_container_add (GTK_CONTAINER (window), bench);
+  gtk_widget_show_all (window);
+  
+  cairo_t *cr;
+  cr = gdk_cairo_create (bench->window);
+
+  // Run tests
+  draw (bench, cr);
+
+  // Hold output on screen until user exits.
+  printf("Press any key to exit.\n");
+  getchar();
+  exit(0);
+gtk_main();
+}