/* * Copyright © 2004 David Reveman, Peter Nilsson * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation, and that the names of * David Reveman and Peter Nilsson not be used in advertising or * publicity pertaining to distribution of the software without * specific, written prior permission. David Reveman and Peter Nilsson * makes no representations about the suitability of this software for * any purpose. It is provided "as is" without express or implied warranty. * * DAVID REVEMAN AND PETER NILSSON DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DAVID REVEMAN AND * PETER NILSSON BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * Authors: David Reveman * Peter Nilsson */ #include #include #include #include #include #include #include #include #include #include #include #define PACKAGE "cairogears" #define WINDOW_WIDTH 512 #define WINDOW_HEIGHT 512 void trap_setup (cairo_surface_t *target, int w, int h); void trap_render (cairo_t *cr, int w, int h); void comp_setup (cairo_surface_t *target, int w, int h); void comp_render (cairo_t *cr, int w, int h); void text_setup (cairo_surface_t *target, int w, int h); void text_render (cairo_t *cr, int w, int h); void text2_setup (cairo_surface_t *target, int w, int h); void text2_render (cairo_t *cr, int w, int h); void shadow_setup (cairo_surface_t *target, int w, int h); void shadow_render (cairo_t *cr, int w, int h); static enum { NONE, STROKE_AND_FILL_TYPE, COMPOSITE_AND_TRANSFORM_TYPE, TEXT_PATH_TYPE, TEXT_BITMAP_TYPE, SHADOW_TYPE } test_type = NONE; static const char *backend = "xrender"; static const char *test; int fast = 0; int fill_gradient = 0; int aa = -1; extern unsigned int glyph_cnt; static unsigned int frame_cnt; static void usage (const char *program_name) { printf ("Usage: %s [-image | -xrender | -gl] [-invisible] TEST\n\n" "\tThe following tests are available:\n\n" "\tTRAP Trapezoid fill test\n" "\tGRAD Trapezoid gradient test\n" "\tCOMP Composite and transform test\n" "\tTEXT Text path test\n" "\tTEXT2 Text bitmap test\n" "\tSHADOW Composite with mask and convolution filter test\n\n", program_name); } static void alarmhandler (int sig) { if (sig == SIGALRM) { if (test_type == TEXT_BITMAP_TYPE) { printf ("%s - %s: %d glyphs in 5.0 seconds = %.3f GPS\n", backend, test, glyph_cnt, glyph_cnt / 5.0); glyph_cnt = 0; } printf ("%s - %s: %d frames in 5.0 seconds = %.3f FPS\n", backend, test, frame_cnt, frame_cnt / 5.0); frame_cnt = 0; } signal (SIGALRM, alarmhandler); alarm(5); } static cairo_device_t * cairogears_gl_context_create(Display *dpy, GLXContext *out_gl_ctx) { int attribs[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 1, None }; GLXContext gl_ctx; XVisualInfo *visinfo; cairo_device_t *ctx; visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), attribs); if (visinfo == NULL) { fprintf(stderr, "Failed to create RGB, double-buffered visual\n"); exit(1); } gl_ctx = glXCreateContext (dpy, visinfo, NULL, True); *out_gl_ctx = gl_ctx; XFree(visinfo); ctx = cairo_glx_device_create (dpy, gl_ctx); return ctx; } int main (int argc, char **argv) { enum { XRENDER_TYPE, IMAGE_TYPE, GL_TYPE, } output_type = XRENDER_TYPE; int visible = 1; GLXContext gl_ctx; Display *dpy; Window win; XWMHints xwmh = { (InputHint|StateHint), False, NormalState, 0, 0, 0, 0, 0, 0, }; XEvent event; XSizeHints xsh; XSetWindowAttributes xswa; unsigned int width, height, window_width, window_height; cairo_surface_t *win_surface; cairo_surface_t *surface; cairo_device_t *ctx = NULL; cairo_t *cr; int i; for (i = 1; i < argc; i++) { if (!strcasecmp ("-image", argv[i])) { output_type = IMAGE_TYPE; backend = "image"; } else if (!strcasecmp ("-xrender", argv[i])) { output_type = XRENDER_TYPE; backend = "xrender"; } else if (!strcasecmp ("-gl", argv[i])) { output_type = GL_TYPE; backend = "gl"; } else if (!strcasecmp ("TRAP", argv[i])) { test_type = STROKE_AND_FILL_TYPE; test = "trapezoids"; } else if (!strcasecmp ("GRAD", argv[i])) { test_type = STROKE_AND_FILL_TYPE; fill_gradient = 1; test = "gradient"; } else if (!strcasecmp ("COMP", argv[i])) { test_type = COMPOSITE_AND_TRANSFORM_TYPE; test = "composite"; } else if (!strcasecmp ("TEXT", argv[i])) { test_type = TEXT_PATH_TYPE; test = "text"; } else if (!strcasecmp ("TEXT2", argv[i])) { test_type = TEXT_BITMAP_TYPE; test = "text2"; } else if (!strcasecmp ("SHADOW", argv[i])) { test_type = SHADOW_TYPE; test = "shadow"; } else if (!strcasecmp ("-invisible", argv[i])) { visible = 0; } else { fprintf (stderr, "%s: unrecognized option `%s'\n", argv[0], argv[i]); usage (argv[0]); exit (1); } } if (test_type == NONE) { usage (argv[0]); exit (1); } window_width = width = WINDOW_WIDTH; window_height = height = WINDOW_HEIGHT; if ((dpy = XOpenDisplay (NULL)) == NULL) { fprintf(stderr, "%s: can't open display: %s\n", argv[0], XDisplayName (NULL)); exit(1); } xsh.flags = PSize; xsh.width = width; xsh.height = height; xsh.x = 0; xsh.y = 0; win = XCreateWindow (dpy, RootWindow (dpy, DefaultScreen (dpy)), xsh.x, xsh.y, xsh.width, xsh.height, 0, CopyFromParent, CopyFromParent, CopyFromParent, 0, &xswa); XSetStandardProperties (dpy, win, PACKAGE, PACKAGE, None, argv, argc, &xsh); XSetWMHints (dpy, win, &xwmh); XSelectInput (dpy, win, StructureNotifyMask); if (output_type != GL_TYPE) { win_surface = cairo_xlib_surface_create (dpy, win, DefaultVisual (dpy, DefaultScreen (dpy)), width, height); } else { ctx = cairogears_gl_context_create(dpy, &gl_ctx); win_surface = cairo_gl_surface_create_for_window(ctx, win, width, height); } switch (output_type) { case XRENDER_TYPE: surface = cairo_surface_create_similar (win_surface, CAIRO_CONTENT_COLOR_ALPHA, width, height); break; case GL_TYPE: surface = cairo_surface_reference (win_surface); break; case IMAGE_TYPE: surface = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32, width, height); break; default: fprintf (stderr, "unknown target surface\n"); exit (1); } if (cairo_surface_status (surface)) { fprintf (stderr, "error constructing surface: %s\n", cairo_status_to_string (cairo_surface_status (surface))); exit (1); } switch (test_type) { case NONE: case STROKE_AND_FILL_TYPE: trap_setup (surface, width, height); break; case COMPOSITE_AND_TRANSFORM_TYPE: comp_setup (surface, width, height); break; case TEXT_PATH_TYPE: text_setup (surface, width, height); break; case TEXT_BITMAP_TYPE: text2_setup (surface, width, height); break; case SHADOW_TYPE: shadow_setup (surface, width, height); break; } cr = cairo_create (surface); cairo_set_tolerance (cr, 0.5); cairo_surface_destroy (surface); surface = NULL; if (cairo_status (cr)) { fprintf (stderr, "error constructing context: %s\n", cairo_status_to_string (cairo_status (cr))); exit (1); } XMapWindow (dpy, win); XSync (dpy, True); if (test_type == TEXT_BITMAP_TYPE) { XSync (dpy, False); usleep (200000); XSync (dpy, False); } signal (SIGALRM, alarmhandler); alarm (5); for (;;) { if (XPending (dpy)) { while (XPending (dpy)) { XNextEvent (dpy, &event); if (event.type == ConfigureNotify) { width = event.xconfigure.width; height = event.xconfigure.height; if (output_type != GL_TYPE) { cairo_xlib_surface_set_size (win_surface, width, height); } else { cairo_gl_surface_set_size (win_surface, width, height); } cairo_surface_destroy (surface); switch (output_type) { case XRENDER_TYPE: surface = cairo_surface_create_similar (win_surface, CAIRO_CONTENT_COLOR_ALPHA, width, height); break; case GL_TYPE: surface = cairo_surface_reference (win_surface); break; case IMAGE_TYPE: surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); break; } } } if (surface != NULL) { cairo_destroy (cr); cr = cairo_create (surface); cairo_set_tolerance (cr, 0.5); cairo_surface_destroy (surface); surface = NULL; if (cairo_status (cr)) { fprintf (stderr, "error constructing context: %s\n", cairo_status_to_string (cairo_status (cr))); exit (1); } } } else { switch (test_type) { case NONE: case STROKE_AND_FILL_TYPE: trap_render (cr, width, height); break; case COMPOSITE_AND_TRANSFORM_TYPE: comp_render (cr, width, height); break; case TEXT_PATH_TYPE: text_render (cr, width, height); break; case TEXT_BITMAP_TYPE: text2_render (cr, width, height); break; case SHADOW_TYPE: shadow_render (cr, width, height); break; } if (visible) { if (output_type != GL_TYPE) { cairo_t *cr2 = cairo_create (win_surface); cairo_set_source_surface (cr2, cairo_get_target (cr), 0, 0); cairo_paint (cr2); if (cairo_status (cr2)) { fprintf (stderr, "test left context in error: %s\n", cairo_status_to_string (cairo_status (cr2))); exit (1); } cairo_destroy (cr2); } else { cairo_gl_surface_swapbuffers (win_surface); } } frame_cnt++; #if 0 { static int frame = 0; if (frame++ > 2) { cairo_destroy(cr); cairo_gl_context_destroy(ctx); glXDestroyContext(dpy, gl_ctx); XCloseDisplay(dpy); exit(1); } } #endif } } exit (1); }