Re: IR tuning

New Message Reply Date view Thread view Subject view Author view

Rob Jenkins (robj++at++quid)
Mon, 18 Nov 1996 09:25:47 -0800


Here's tenmillion.c, an iR OpenGL performance test for triangles in a display
list by Phil Lacroute here at SGI. It shows how to achieve optimum numbers:

--------------------------------------------------------------------
/*
 * tenmillion.c
 *
 * OpenGL performance test for triangles in a display list.
 * lacroute++at++asd.sgi.com, March 1996
 *
 * To compile:
 * cc -o tenmillion -O2 tenmillion.c -lGLU -lGL -lX11 -lm
 *
 * To run:
 * tenmillion [options]
 * tenmillion help
 */

/*
 * Notes on using this program with InfiniteReality
 * ------------------------------------------------
 *
 * On a 4RM InfiniteReality this program draws over
 * 10-million 50-pixel triangles/sec. Just type:
 * tenmillion
 * On machines with only one or two RMs the performance
 * is lower because the machine is fill-limited. You
 * can still achieve over 10 million triangles/sec if
 * you use a smaller triangle size. For a 2RM system
 * use a 12 pixel triangle:
 * tenmillion area=12
 * For a 1RM system use a 3 pixel triangle:
 * tenmillion area=3
 * Note that when you double the number of RMs the
 * size of the triangle you can use more than doubles.
 * (The super-linear speedup is due to edge effects:
 * larger triangles have a higher area-to-circumference
 * ratio.)
 *
 * Here are some examples for a 1RM system.
 *
 * Unlit, untextured, zbuffered triangles: (11.3 million triangles/sec)
 * tenmillion area=3 zbuffer
 *
 * Lit, untextured, zbuffered triangles: (8.0 million triangles/sec)
 * tenmillion area=3 light smooth zbuffer
 *
 * Unlit, textured, zbuffered triangles: (7.8 million triangles/sec)
 * tenmillion area=3 texture zbuffer
 *
 * Lit, textured, zbuffered triangles: (6.1 million triangles/sec)
 * tenmillion area=3 light smooth texture zbuffer
 *
 * Fill rate for large, untextured, non-zbuffered triangles: (225 Mpixels/sec)
 * tenmillion area=10000
 *
 * Fill rate for large, untextured, zbuffered triangles: (223 Mpixels/sec)
 * tenmillion area=10000 zbuffer
 *
 * Fill rate for large, textured, non-zbuffered triangles: (196 Mpixels/sec)
 * tenmillion area=10000 texture
 *
 * Fill rate for large, textured, zbuffered triangles: (194 Mpixels/sec)
 * tenmillion area=10000 zbuffer texture
 */

#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <time.h>
#include <ctype.h>
#include <string.h>
#include <GL/glx.h>
#include <GL/glu.h>
#include <math.h>

#define TEXTURE_SIZE 64 /* texture dimension (texels/side) */
#define TEXTURE_LOD 0.5 /* texture level-of-detail */
#define MARGIN 10 /* margin around mesh (pixels) */
#define MAX_WIN_SIZE 850 /* maximum window width/height */
#define DEFAULT_STRIPLEN 90 /* preferred strip length */
#define DEFAULT_STRIPS 1 /* preferred number of strips */
#define TEST_DURATION 2.0 /* test duration in seconds */
#define DLIST_NAME 1 /* display list name */

Display *display; /* connection to X server */
XVisualInfo *vi; /* window visual */
Window window; /* window for drawing */
GLXContext context; /* graphics context */
unsigned win_w, win_h; /* window size */
int striplen; /* triangles/strip */
int strips; /* number of strips */
float xsize, ysize, xoffset; /* triangle base, height, and apex offset */

int texture = 0; /* if true, enable texturing */
int light = 0; /* if true, enable lighting */
int smooth = 0; /* if true, use smooth shading */
int zbuffer = 0; /* if true, enable zbuffer */
int area = 50; /* triangle area in pixels */

#define NUM_ANGLES 8
float angles[NUM_ANGLES] = {0, 22.5, 45, 67.5, 90, 112.5, 135, 157.5};

int RGBattributes[] = {
    GLX_RGBA,
    GLX_RED_SIZE, 8,
    GLX_GREEN_SIZE, 8,
    GLX_BLUE_SIZE, 8,
    None
};

int RGBZattributes[] = {
    GLX_RGBA,
    GLX_RED_SIZE, 8,
    GLX_GREEN_SIZE, 8,
    GLX_BLUE_SIZE, 8,
    GLX_DEPTH_SIZE, 16,
    None
};

/*
 * help
 *
 * Print a usage message.
 */

void
help(void)
{
    printf("Usage: tenmillion [options]\n\n");
    printf("Options:\n"
           " texture enable texture mapping (mipmapped)\n"
           " light enable lighting (one infinite light)\n"
           " smooth enable smooth shading (Gouraud)\n"
           " zbuffer enable zbuffer\n"
           " area=N set triangle area to N pixels\n");
    exit(0);
}

/*
 * parse_args
 *
 * Parse the command line arguments.
 */

void
parse_args(int argc, char **argv)
{
    float w, h;

    while (--argc) {
        ++argv;
        if (!strcmp(*argv, "texture")) {
            texture = 1;
        } else if (!strcmp(*argv, "light")) {
            light = 1;
        } else if (!strcmp(*argv, "smooth")) {
            smooth = 1;
        } else if (!strcmp(*argv, "zbuffer")) {
            zbuffer = 1;
        } else if (!strncmp(*argv, "area=", 5)) {
            area = strtol(*argv+5, NULL, 0);
        } else {
            fprintf(stderr, "unrecognized argument %s\n", *argv);
            help();
        }
    }

    /* compute triangle dimensions from triangle size */
    xsize = sqrt(2 * area);
    ysize = 2 * area / xsize;
    xoffset = xsize/2;

    /* compute strip length and number of strips */
    if (xsize*(DEFAULT_STRIPLEN+1)/2 + xoffset + 2*MARGIN > MAX_WIN_SIZE) {
        striplen = 2*(MAX_WIN_SIZE - xoffset - 2*MARGIN) / xsize;
        if (striplen < 2)
            striplen = 2;
    } else {
        striplen = DEFAULT_STRIPLEN;
    }
    strips = 10/ysize;
    if (strips < 1)
        strips = 1;
    if (ysize*strips + 2*MARGIN > MAX_WIN_SIZE) {
        strips = (MAX_WIN_SIZE - 2*MARGIN) / ysize;
        if (strips < 1)
            strips = 1;
    }

    /* compute window size */
    w = xsize*((striplen+1)/2) + 2*MARGIN;
    if ((striplen & 1) == 0)
        w += xoffset;
    h = ysize*strips + 2*MARGIN;
    win_w = 2*(int)ceil(sqrt(w*w/4 + h*h/4));
    if (win_w < 300)
        win_w = 300;
    if (win_w > MAX_WIN_SIZE) {
        fprintf(stderr, "Triangle area is too large to fit.\n");
        exit(1);
    }
    win_h = win_w;
}

/*
 * wait_for_map_notify
 *
 * Callback for XIfEvent.
 */

int
wait_for_map_notify(Display *display, XEvent *event, char *arg)
{
    return(event->type == MapNotify && event->xmap.window == (Window)arg);
}

/*
 * open_window
 *
 * Create an X window.
 */

void
open_window(void)
{
    XSetWindowAttributes swa;
    XSizeHints hints;
    XEvent event;
    XVisualInfo template;
    int c, x, y;

    display = XOpenDisplay(0);
    if (display == NULL) {
        fprintf(stderr, "Can't connect to display \"%s\"\n",
                getenv("DISPLAY"));
        exit(1);
    }
    vi = glXChooseVisual(display, DefaultScreen(display),
                         zbuffer ? RGBZattributes : RGBattributes);
    if (vi == NULL) {
        fprintf(stderr, "can't find appropriate visual\n");
        exit(1);
    }
    swa.border_pixel = 0;
    swa.colormap = XCreateColormap(display, RootWindow(display, vi->screen),
                                   vi->visual, AllocNone);
    swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask;
    x = (DisplayWidth(display, vi->screen) - win_w) / 2;
    y = (DisplayHeight(display, vi->screen) - win_h) / 2;
    window = XCreateWindow(display, RootWindow(display, vi->screen),
                           x, y, win_w, win_h,
                           0, vi->depth, InputOutput, vi->visual,
                           CWBorderPixel | CWColormap | CWEventMask, &swa);
    if (window == 0) {
        fprintf(stderr, "could not create a window\n");
        exit(1);
    }
    XStoreName(display, window, "InfiniteReality Speed Demo");
    hints.x = x;
    hints.y = y;
    hints.width = win_w;
    hints.height = win_h;
    hints.flags = USPosition | PSize;
    XSetNormalHints(display, window, &hints);
    XMapWindow(display, window);
    XIfEvent(display, &event, wait_for_map_notify, (char *)window);
    context = glXCreateContext(display, vi, 0, GL_TRUE);
    glXMakeCurrent(display, window, context);
    glViewport(0, 0, win_w, win_h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, win_w, 0, win_h, -1, 1);
    glMatrixMode(GL_MODELVIEW);
}

/*
 * compile_test
 *
 * Compile a test into a display list.
 */

void
compile_test(void)
{
    float *vdata; /* array containing vertex data */
    float *vptr; /* pointer to data for current vertex */
    int r; /* current row number */
    int v; /* current vertex number within row */
    int a; /* angle number */
    float x, y, tx, ty, c, s;

    /* compute mesh data */
    vdata = memalign(16, NUM_ANGLES*(striplen+2)*strips*2*sizeof(float));
    if (vdata == NULL) {
        fprintf(stderr, "could not allocate memory for mesh data\n");
        exit(1);
    }
    vptr = vdata;
    tx = -(xsize * ((striplen+1)/2) + ((striplen & 1) ? 0 : xoffset))/2;
    ty = -ysize*strips/2;
    for (a = 0; a < NUM_ANGLES; a++) {
        c = cos(angles[a]*M_PI/180);
        s = sin(angles[a]*M_PI/180);
        for (r = 0; r < strips; r++) {
            for (v = 0; v < striplen+2; v++) {
                if (v & 1) {
                    x = (v/2)*xsize + xoffset + tx;
                    y = (r+1)*ysize + ty;
                } else {
                    x = (v/2)*xsize + tx;
                    y = r*ysize + ty;
                }
                vptr[0] = win_w/2 + c*x - s*y;
                vptr[1] = win_h/2 + s*x + c*y;
                vptr += 2;
            }
        }
    }

    /* create display list */
    vptr = vdata;
    glNewList(DLIST_NAME, GL_COMPILE);
        for (a = 0; a < NUM_ANGLES; a++) {
            for (r = 0; r < strips; r++) {
                glBegin(GL_TRIANGLE_STRIP);
                for (v = 0; v < striplen+2; v++) {
                    if (light) {
                        glNormal3s((v&1) ? 0 : 32767, 0, (v&1) ? 32767 : 0);
                    }
                    if (texture) {
                        /* use vertex coordinates for texture coordinates */
                        glTexCoord2s((short)vptr[0], (short)vptr[1]);
                    }
                    glVertex3f(vptr[0], vptr[1], 0);
                    vptr += 2;
                }
                glEnd();
            }
        }
    glEndList();
    free(vdata);
}

/*
 * make_texture
 *
 * Create a checkerboard texture.
 */

GLubyte *
make_texture(void)
{
    int i, j, c;
    GLubyte *texdata, *tptr;

    if ((texdata = malloc(TEXTURE_SIZE*TEXTURE_SIZE*3)) == NULL) {
        fprintf(stderr, "not enough memory for texture data\n");
        exit(1);
    }
    tptr = texdata;
    for (j = 0; j < TEXTURE_SIZE; j++) {
        for (i = 0; i < TEXTURE_SIZE; i++) {
            c = (((i&8) == 0) ^ ((j&8) == 0)) * 255;
            tptr[0] = (GLubyte)c;
            tptr[1] = (GLubyte)c;
            tptr[2] = (GLubyte)c;
            tptr += 3;
        }
    }
    return(texdata);
}

/*
 * init_test
 *
 * Initialize graphics state for a test. This code is not timed.
 */

void
init_test(void)
{
    int l;
    static float light_color[4] = {0, 1, 0, 1};
    static float light_pos[4] = {1, 1, -1, 0};
    float texture_scale;
    GLubyte *texdata;

    glDrawBuffer(GL_FRONT);
    glClearColor(0.5,0.5,0.5,0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(1,1,1);
    glFrontFace(GL_CW);
    if (smooth) {
        glShadeModel(GL_SMOOTH);
    } else {
        glShadeModel(GL_FLAT);
    }
    if (zbuffer) {
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LEQUAL);
    } else {
        glDisable(GL_DEPTH_TEST);
    }
    if (light) {
        glEnable(GL_LIGHTING);
        glEnable(GL_LIGHT0);
        glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
        glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color);
        glLightfv(GL_LIGHT0, GL_SPECULAR, light_color);
    } else {
        glDisable(GL_LIGHTING);
    }
    if (texture) {
        texdata = make_texture();
        if (light)
            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
        else
            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                        GL_LINEAR_MIPMAP_LINEAR);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA4_EXT,
                          TEXTURE_SIZE, TEXTURE_SIZE,
                          GL_RGB, GL_UNSIGNED_BYTE, texdata);

        glMatrixMode(GL_TEXTURE);
        glLoadIdentity();
        texture_scale = pow(2, TEXTURE_LOD) / (double)TEXTURE_SIZE;
        glScalef(texture_scale, texture_scale, 1);
        glMatrixMode(GL_MODELVIEW);
        glEnable(GL_TEXTURE_2D);
    } else {
        glDisable(GL_TEXTURE_2D);
    }
}

/*
 * get_clock
 *
 * Get current time (expressed in seconds).
 */

double
get_clock(void)
{
    struct timeval t;

    gettimeofday(&t);
    return((double)t.tv_sec + (double)t.tv_usec*1E-6);
}

/*
 * benchmark
 *
 * Run the benchmark.
 */

void
benchmark(void)
{
    time_t t;
    char machine[MAXHOSTNAMELEN+1];
    long reps, i;
    double start, current;
    float frame_rate;
    GLenum error;

    /* print information about the test */
    t = time(0);
    gethostname(machine, MAXHOSTNAMELEN);
    machine[MAXHOSTNAMELEN] = '\0';
    printf("running on %s (%s) %s",
           machine, glGetString(GL_RENDERER), ctime(&t));
    printf("visual: 0x%x\n", vi->visualid);
    printf("%d pixel triangles, %d triangles/strip, %d strips\n",
           area, striplen, strips);
    printf("vertex data:");
    if (light)
        printf(" n3s");
    if (texture)
        printf(" t2s");
    printf(" v3f\n");
    printf("%s shading, zbuffer %s, light %s, texture %s\n",
           smooth ? "smooth" : "flat",
           zbuffer ? "on" : "off",
           light ? "on" : "off",
           texture ? "on" : "off");

    /* initialize and run the test once to make sure
       display list is in the cache */
    compile_test();
    init_test();
    glCallList(DLIST_NAME);

    /* calibration loop */
    glFinish();
    reps = 1;
    current = 0;
    start = 0;
    while ((current - start) < TEST_DURATION/4) {
        reps = reps * 2;
        start = get_clock();
        while ((current = get_clock()) == start) /* wait for next tick */
            ;
        start = current;
        for (i = reps; i > 0; --i)
            glCallList(DLIST_NAME);
        glFinish();
        current = get_clock();
    }
    reps = reps * (TEST_DURATION / (current - start));
    if (reps < 1)
        reps = 1;

    /* timing loop */
    start = get_clock();
    while ((current = get_clock()) == start) /* wait for next tick */
        ;
    start = current;
    for (i = reps; i > 0; --i)
        glCallList(DLIST_NAME);
    glFinish();
    current = get_clock();
    frame_rate = reps / (current - start);
    while ((error = glGetError()) != GL_NO_ERROR)
        fprintf(stderr, "GL Error: %s\n", (char *)gluErrorString(error));
    printf("test time: %.3f secs.\n", current - start);

    /* print results */
    printf("geometry rate: %.0f triangles/sec\n",
           NUM_ANGLES*strips*striplen*frame_rate);
    printf("fill rate: %.3f Mpixels/sec\n",
           area*NUM_ANGLES*strips*striplen*frame_rate/1e6);
}

void
main(int argc, char **argv)
{
    parse_args(argc, argv);
    open_window();
    benchmark();
}

-- 
________________________________________________________________
Rob Jenkins mailto:robj++at++csd.sgi.com
Silicon Graphics, Mtn View, California, USA
=======================================================================
List Archives, FAQ, FTP:  http://www.sgi.com/Technology/Performer/
            Submissions:  info-performer++at++sgi.com
        Admin. requests:  info-performer-request++at++sgi.com

New Message Reply Date view Thread view Subject view Author view

This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:53:58 PDT

This message has been cleansed for anti-spam protection. Replace '++at++' in any mail addresses with the '@' symbol.