1 /* Copyright (C)2007 Sun Microsystems, Inc.
2 * Copyright (C)2011, 2013 D. R. Commander
4 * This library is free software and may be redistributed and/or modified under
5 * the terms of the wxWindows Library License, Version 3.1 or (at your option)
6 * any later version. The full license is in the LICENSE.txt file included
7 * with this distribution.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * wxWindows Library License for more details.
15 /* This program's goal is to reproduce, as closely as possible, the image
16 output of the nVidia SphereMark demo by R. Stephen Glanville using the
17 simplest available rendering method. GLXSpheres is meant primarily to
18 serve as an image pipeline benchmark for VirtualGL. */
34 //#include "rrtimer.h"
37 #define min(a, b) (((a) < (b)) ? (a) : (b))
39 static double rrtime()
41 struct timeval cur_time;
42 gettimeofday(&cur_time, NULL);
43 return ((unsigned long long)(cur_time.tv_sec) * 1000000ULL + (unsigned long long)(cur_time.tv_usec)) / 1000000.0;
48 fprintf(stderr, "ERROR (%d): %s\n", __LINE__, m); \
51 #define np2(i) ((i) > 0 ? (1 << (int)(log((double)(i)) / log(2.))) : 0)
58 #define spherered(f) fabs(MAXI *(2. * f - 1.))
59 #define spheregreen(f) fabs(MAXI *(2. * fmod(f + 2. / 3., 1.) - 1.))
60 #define sphereblue(f) fabs(MAXI *(2. * fmod(f + 1. / 3., 1.) - 1.))
62 #define DEF_WIDTH 1240
63 #define DEF_HEIGHT 900
70 #define _2PI 6.283185307180
71 #define MAXI (220. / 255.)
85 #define DEFBENCHTIME 2.0
88 Window win = 0, olwin = 0;
89 int usestereo = 0, useoverlay = 0, useci = 0, useimm = 0, interactive = 0, oldb = 1,
90 locolor = 0, maxframes = 0, totalframes = 0, directctx = True;
91 double benchtime = DEFBENCHTIME;
92 int ncolors = 0, nolcolors, colorscheme = GREY;
93 Colormap colormap = 0, olcolormap = 0;
94 GLXContext ctx = 0, olctx = 0;
96 int spherelist = 0, fontlistbase = 0;
97 GLUquadricObj *spherequad = NULL;
98 int slices = DEF_SLICES, stacks = DEF_STACKS;
99 float x = 0., y = 0., z = -3.;
100 float outer_angle = 0., middle_angle = 0., inner_angle = 0.;
101 float lonesphere_color = 0.;
102 unsigned int transpixel = 0;
104 int width = DEF_WIDTH, height = DEF_HEIGHT;
106 int setcolorscheme(Colormap c, int nc, int scheme)
111 _throw("Color map not allocated");
112 if (scheme < 0 || scheme > NSCHEMES - 1 || !c)
113 _throw("Invalid argument");
115 for (i = 0; i < nc; i++)
117 xc[i].flags = DoRed | DoGreen | DoBlue;
119 xc[i].red = xc[i].green = xc[i].blue = 0;
120 if (scheme == GREY || scheme == RED || scheme == YELLOW || scheme == MAGENTA)
121 xc[i].red = (i * (256 / nc)) << 8;
122 if (scheme == GREY || scheme == GREEN || scheme == YELLOW || scheme == CYAN)
123 xc[i].green = (i * (256 / nc)) << 8;
124 if (scheme == GREY || scheme == BLUE || scheme == MAGENTA || scheme == CYAN)
125 xc[i].blue = (i * (256 / nc)) << 8;
127 XStoreColors(dpy, c, xc, nc);
134 void reshape(int w, int h)
136 XWindowChanges changes;
143 if (useoverlay && olwin)
145 changes.width = width;
146 changes.height = height;
147 XConfigureWindow(dpy, olwin, CWWidth | CWHeight, &changes);
151 void setspherecolor(float c)
155 GLfloat ndx = c * (float)(ncolors - 1);
156 GLfloat mat_ndxs[] = { ndx * 0.3, ndx * 0.8, ndx };
158 glMaterialfv(GL_FRONT, GL_COLOR_INDEXES, mat_ndxs);
162 float mat[4] = { spherered(c), spheregreen(c), sphereblue(c), 0.25 };
163 glColor3f(spherered(c), spheregreen(c), sphereblue(c));
164 glMaterialfv(GL_FRONT, GL_AMBIENT, mat);
165 glMaterialfv(GL_FRONT, GL_DIFFUSE, mat);
169 void renderspheres(int buf)
172 GLfloat xaspect, yaspect;
173 GLfloat stereocameraoffset = 0.;
174 GLfloat neardist = 1.5, fardist = 40., zeroparallaxdist = 17.;
177 xaspect = (GLfloat)width / (GLfloat)(min(width, height));
178 yaspect = (GLfloat)height / (GLfloat)(min(width, height));
180 if (buf == GL_BACK_LEFT)
181 stereocameraoffset = -xaspect * zeroparallaxdist / neardist * 0.035;
182 else if (buf == GL_BACK_RIGHT)
183 stereocameraoffset = xaspect * zeroparallaxdist / neardist * 0.035;
185 glMatrixMode(GL_PROJECTION);
187 glFrustum(-xaspect, xaspect, -yaspect, yaspect, neardist, fardist);
188 glTranslatef(-stereocameraoffset, 0., 0.);
189 glMatrixMode(GL_MODELVIEW);
190 glViewport(0, 0, width, height);
193 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
195 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
199 glTranslatef(0., 0., z);
200 setspherecolor(lonesphere_color);
202 gluSphere(spherequad, 1.3, slices, stacks);
204 glCallList(spherelist);
209 glRotatef(outer_angle, 0., 0., 1.);
210 for (i = 0; i < NSPHERES; i++)
212 double f = (double)i / (double)NSPHERES;
214 glTranslatef(sin(_2PI * f) * 5., cos(_2PI * f) * 5., -10.);
217 gluSphere(spherequad, 1.3, slices, stacks);
219 glCallList(spherelist);
226 glRotatef(middle_angle, 0., 0., 1.);
227 for (i = 0; i < NSPHERES; i++)
229 double f = (double)i / (double)NSPHERES;
231 glTranslatef(sin(_2PI * f) * 5., cos(_2PI * f) * 5., -17.);
234 gluSphere(spherequad, 1.3, slices, stacks);
236 glCallList(spherelist);
243 glRotatef(inner_angle, 0., 0., 1.);
244 for (i = 0; i < NSPHERES; i++)
246 double f = (double)i / (double)NSPHERES;
248 glTranslatef(sin(_2PI * f) * 5., cos(_2PI * f) * 5., -29.);
251 gluSphere(spherequad, 1.3, slices, stacks);
253 glCallList(spherelist);
258 // Move the eye back to the middle
259 glMatrixMode(GL_PROJECTION);
260 glTranslatef(stereocameraoffset, 0., 0.);
263 void renderoverlay(void)
265 int i, j, w = width / 8, h = height / 8;
266 unsigned char *buf = NULL;
267 int ndx = (int)(lonesphere_color * (float)(nolcolors - 1));
268 glShadeModel(GL_FLAT);
269 glDisable(GL_DEPTH_TEST);
270 glDisable(GL_LIGHTING);
271 glMatrixMode(GL_PROJECTION);
273 glMatrixMode(GL_MODELVIEW);
274 glViewport(0, 0, width, height);
275 glRasterPos3f(-0.5, 0.5, 0.0);
276 glClearIndex((float)transpixel);
277 glClear(GL_COLOR_BUFFER_BIT);
278 glIndexf(lonesphere_color * (float)(nolcolors - 1));
280 glVertex2f(-1. + lonesphere_color * 2., -1.);
281 glVertex2f(-1. + lonesphere_color * 2., 1.);
282 glVertex2f(-1., -1. + lonesphere_color * 2.);
283 glVertex2f(1., -1. + lonesphere_color * 2.);
287 if ((buf = (unsigned char *)malloc(w * h)) == NULL)
288 _throw("Could not allocate memory");
289 for (i = 0; i < h; i++)
290 for (j = 0; j < w; j++)
292 if (((i / 4) % 2) != ((j / 4) % 2))
295 buf[i * w + j] = ndx;
297 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
298 glDrawPixels(w, h, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, buf);
300 glRasterPos3f(0., 0., 0.);
301 glListBase(fontlistbase);
302 glCallLists(24, GL_UNSIGNED_BYTE, "GLX Spheres Overlay Test");
308 int display(int advance)
310 static int first = 1;
311 static double start = 0., elapsed = 0., mpixels = 0.;
312 static unsigned long frames = 0;
313 static char temps[256];
314 XFontStruct *fontinfo = NULL;
315 int minchar, maxchar;
316 GLfloat xaspect, yaspect;
320 GLfloat id4[] = { 1., 1., 1., 1. };
321 GLfloat light0_amb[] = { 0.3, 0.3, 0.3, 1. };
322 GLfloat light0_dif[] = { 0.8, 0.8, 0.8, 1. };
323 GLfloat light0_pos[] = { 1., 1., 1., 0. };
325 spherelist = glGenLists(1);
326 if (!(spherequad = gluNewQuadric()))
327 _throw("Could not allocate GLU quadric object");
328 glNewList(spherelist, GL_COMPILE);
329 gluSphere(spherequad, 1.3, slices, stacks);
336 glMaterialf(GL_FRONT, GL_SHININESS, 50.);
340 glMaterialfv(GL_FRONT, GL_AMBIENT, id4);
341 glMaterialfv(GL_FRONT, GL_DIFFUSE, id4);
342 glMaterialfv(GL_FRONT, GL_SPECULAR, id4);
343 glMaterialf(GL_FRONT, GL_SHININESS, 50.);
345 glLightfv(GL_LIGHT0, GL_AMBIENT, light0_amb);
346 glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_dif);
347 glLightfv(GL_LIGHT0, GL_SPECULAR, id4);
349 glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);
350 glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 180.);
351 glEnable(GL_LIGHTING);
356 glShadeModel(GL_FLAT);
358 glShadeModel(GL_SMOOTH);
359 glEnable(GL_DEPTH_TEST);
360 glDepthFunc(GL_LESS);
364 glXMakeCurrent(dpy, olwin, olctx);
366 if (!(fontinfo = XLoadQueryFont(dpy, "fixed")))
367 _throw("Could not load X font");
368 minchar = fontinfo->min_char_or_byte2;
369 maxchar = fontinfo->max_char_or_byte2;
370 fontlistbase = glGenLists(maxchar + 1);
371 glXUseXFont(fontinfo->fid, minchar, maxchar - minchar + 1, fontlistbase + minchar);
372 XFreeFont(dpy, fontinfo);
374 snprintf(temps, 255, "Measuring performance ...");
376 glXMakeCurrent(dpy, win, ctx);
386 if (useci || useoverlay)
387 colorscheme = (colorscheme + 1) % NSCHEMES;
389 _catch(setcolorscheme(colormap, ncolors, colorscheme));
391 _catch(setcolorscheme(olcolormap, nolcolors, colorscheme));
395 if (outer_angle > 360.)
397 middle_angle -= 0.37;
398 if (middle_angle < -360.)
399 middle_angle += 360.;
401 if (inner_angle > 360.)
403 lonesphere_color += 0.005;
404 if (lonesphere_color > 1.)
405 lonesphere_color -= 1.;
410 renderspheres(GL_BACK_LEFT);
411 renderspheres(GL_BACK_RIGHT);
414 renderspheres(GL_BACK);
416 glDrawBuffer(GL_BACK);
419 glXMakeCurrent(dpy, olwin, olctx);
423 glPushAttrib(GL_CURRENT_BIT);
424 glPushAttrib(GL_LIST_BIT);
425 glPushAttrib(GL_ENABLE_BIT);
426 glDisable(GL_LIGHTING);
427 if (useoverlay || useci)
430 glColor3f(1., 1., 1.);
432 glRasterPos3f(-0.95, -0.95, 0.);
435 xaspect = (GLfloat)width / (GLfloat)(min(width, height));
436 yaspect = (GLfloat)height / (GLfloat)(min(width, height));
437 glRasterPos3f(-0.95 * xaspect, -0.95 * yaspect, -1.5);
439 glListBase(fontlistbase);
440 glCallLists(strlen(temps), GL_UNSIGNED_BYTE, temps);
447 glXSwapBuffers(dpy, olwin);
448 glXMakeCurrent(dpy, win, ctx);
450 glXSwapBuffers(dpy, win);
455 elapsed += rrtime() - start;
458 mpixels += (double)width * (double)height / 1000000.;
459 if (elapsed > benchtime || (maxframes && totalframes > maxframes))
461 snprintf(temps, 255, "%f frames/sec - %f Mpixels/sec",
462 (double)frames / elapsed, mpixels / elapsed);
463 printf("%s\n", temps);
464 elapsed = mpixels = 0.;
468 if (maxframes && totalframes > maxframes)
478 gluDeleteQuadric(spherequad);
483 XFreeFont(dpy, fontinfo);
489 Atom protoatom = 0, deleteatom = 0;
491 int event_loop(Display *dpy)
495 int advance = 0, dodisplay = 0;
501 XNextEvent(dpy, &event);
504 if (XPending(dpy) > 0)
505 XNextEvent(dpy, &event);
514 case ConfigureNotify:
515 reshape(event.xconfigure.width, event.xconfigure.height);
522 key = XLookupString(&event.xkey, buf, sizeof(buf), NULL, NULL);
533 if (event.xmotion.state & Button1Mask)
534 dodisplay = advance = 1;
538 XClientMessageEvent *cme = (XClientMessageEvent *)&event;
539 if (cme->message_type == protoatom && cme->data.l[0] == (long)deleteatom)
545 if (XPending(dpy) <= 0)
557 _catch(display(advance));
566 void usage(char **argv)
568 printf("\nUSAGE: %s [options]\n\n", argv[0]);
569 printf("Options:\n");
570 printf("-c = Use color index rendering (default is RGB)\n");
571 printf("-fs = Full-screen mode\n");
572 printf("-i = Interactive mode. Frames advance in response to mouse movement\n");
573 printf("-l = Use fewer than 24 colors (to force non-JPEG encoding in TurboVNC)\n");
574 printf("-m = Use immediate mode rendering (default is display list)\n");
575 printf("-o = Test 8-bit transparent overlays\n");
576 printf("-p <p> = Use (approximately) <p> polygons to render scene\n");
577 printf("-s = Use stereographic rendering initially\n");
578 printf(" (this can be switched on and off in the application)\n");
579 printf("-32 = Use 32-bit visual (default is 24-bit)\n");
580 printf("-f <n> = max frames to render\n");
581 printf("-bt <t> = print benchmark results every <t> seconds (default=%.1f)\n",
583 printf("-w <wxh> = specify window width and height\n");
584 printf("-ic = Use indirect rendering context\n");
585 printf("-sc <s> = Create window on X screen # <s>\n");
590 int main(int argc, char **argv)
593 XVisualInfo *v = NULL;
594 int rgbattribs[] = { GLX_RGBA, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8,
595 GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 1, GLX_DOUBLEBUFFER, None, None, None,
597 int ciattribs[] = { GLX_BUFFER_SIZE, 8, GLX_DEPTH_SIZE, 1, GLX_DOUBLEBUFFER,
599 int olattribs[] = { GLX_BUFFER_SIZE, 8, GLX_LEVEL, 1, GLX_TRANSPARENT_TYPE,
600 GLX_TRANSPARENT_INDEX, GLX_DOUBLEBUFFER, None };
601 XSetWindowAttributes swa;
604 unsigned long mask = 0;
607 for (i = 0; i < argc; i++)
609 if (!strncasecmp(argv[i], "-h", 2))
611 if (!strncasecmp(argv[i], "-?", 2))
613 if (!strncasecmp(argv[i], "-c", 2))
615 if (!strncasecmp(argv[i], "-ic", 3))
617 else if (!strncasecmp(argv[i], "-i", 2))
619 if (!strncasecmp(argv[i], "-l", 2))
621 if (!strncasecmp(argv[i], "-m", 2))
623 if (!strncasecmp(argv[i], "-o", 2))
625 if (!strncasecmp(argv[i], "-w", 2) && i < argc - 1)
628 if (sscanf(argv[++i], "%dx%d", &w, &h) == 2 && w > 0 && h > 0)
632 printf("Window dimensions: %d x %d\n", width, height);
635 if (!strncasecmp(argv[i], "-p", 2) && i < argc - 1)
637 int npolys = atoi(argv[++i]);
640 slices = stacks = (int)(sqrt((double)npolys / ((double)(3 * NSPHERES + 1))));
645 if (!strncasecmp(argv[i], "-fs", 3))
647 else if (!strncasecmp(argv[i], "-f", 2) && i < argc - 1)
649 int mf = atoi(argv[++i]);
653 printf("Number of frames to render: %d\n", maxframes);
656 if (!strncasecmp(argv[i], "-bt", 3) && i < argc - 1)
658 double temp = atof(argv[++i]);
662 if (!strncasecmp(argv[i], "-sc", 3) && i < argc - 1)
664 int sc = atoi(argv[++i]);
668 printf("Rendering to screen %d\n", screen);
671 else if (!strncasecmp(argv[i], "-s", 2))
673 rgbattribs[10] = GLX_STEREO;
676 if (!strncasecmp(argv[i], "-32", 3))
682 if (rgbattribs[10] == None)
684 rgbattribs[10] = GLX_ALPHA_SIZE;
689 rgbattribs[11] = GLX_ALPHA_SIZE;
694 fprintf(stderr, "Polygons in scene: %d\n", (NSPHERES * 3 + 1) * slices * stacks);
696 if ((dpy = XOpenDisplay(0)) == NULL)
697 _throw("Could not open display");
699 screen = DefaultScreen(dpy);
703 if ((v = glXChooseVisual(dpy, screen, ciattribs)) == NULL)
704 _throw("Could not obtain index visual");
708 if ((v = glXChooseVisual(dpy, screen, rgbattribs)) == NULL)
709 _throw("Could not obtain RGB visual with requested properties");
711 fprintf(stderr, "Visual ID of %s: 0x%.2x\n", useoverlay ? "underlay" : "window",
714 root = RootWindow(dpy, screen);
715 swa.border_pixel = 0;
716 swa.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
717 swa.override_redirect = fullscreen ? True : False;
720 swa.colormap = colormap = XCreateColormap(dpy, root, v->visual, AllocAll);
721 ncolors = np2(v->colormap_size);
723 _throw("Color map is not large enough");
724 _catch(setcolorscheme(colormap, ncolors, colorscheme));
727 swa.colormap = XCreateColormap(dpy, root, v->visual, AllocNone);
730 swa.event_mask |= PointerMotionMask | ButtonPressMask;
732 mask = CWBorderPixel | CWColormap | CWEventMask;
735 mask |= CWOverrideRedirect;
736 width = DisplayWidth(dpy, screen);
737 height = DisplayHeight(dpy, screen);
739 if (!(protoatom = XInternAtom(dpy, "WM_PROTOCOLS", False)))
740 _throw("Cannot obtain WM_PROTOCOLS atom");
741 if (!(deleteatom = XInternAtom(dpy, "WM_DELETE_WINDOW", False)))
742 _throw("Cannot obtain WM_DELETE_WINDOW atom");
743 if ((win = XCreateWindow(dpy, root, 0, 0, width, height, 0, v->depth,
744 InputOutput, v->visual, mask, &swa)) == 0)
745 _throw("Could not create window");
746 XSetWMProtocols(dpy, win, &deleteatom, 1);
747 XStoreName(dpy, win, "GLX Spheres");
748 XMapWindow(dpy, win);
750 XSetInputFocus(dpy, win, RevertToParent, CurrentTime);
753 if ((ctx = glXCreateContext(dpy, v, NULL, directctx)) == 0)
754 _throw("Could not create rendering context");
755 fprintf(stderr, "Context is %s\n",
756 glXIsDirect(dpy, ctx) ? "Direct" : "Indirect");
762 if ((v = glXChooseVisual(dpy, screen, olattribs)) == NULL)
766 if ((v = glXChooseVisual(dpy, screen, olattribs)) == NULL)
767 _throw("Could not obtain overlay visual");
769 fprintf(stderr, "Visual ID of overlay: 0x%.2x\n", (int)v->visualid);
771 swa.colormap = olcolormap = XCreateColormap(dpy, root, v->visual, AllocAll);
772 nolcolors = np2(v->colormap_size);
774 _throw("Color map is not large enough");
776 _catch(setcolorscheme(olcolormap, nolcolors, colorscheme));
778 if ((olwin = XCreateWindow(dpy, win, 0, 0, width, height, 0, v->depth,
779 InputOutput, v->visual, CWBorderPixel | CWColormap | CWEventMask, &swa)) == 0)
780 _throw("Could not create overlay window");
781 XMapWindow(dpy, olwin);
784 if ((olctx = glXCreateContext(dpy, v, NULL, directctx)) == 0)
785 _throw("Could not create overlay rendering context");
786 fprintf(stderr, "Overlay context is %s\n",
787 glXIsDirect(dpy, olctx) ? "Direct" : "Indirect");
793 if (!glXMakeCurrent(dpy, win, ctx))
794 _throw("Could not bind rendering context");
796 fprintf(stderr, "OpenGL Renderer: %s\n", glGetString(GL_RENDERER));
798 _catch(event_loop(dpy));
802 glXDestroyContext(dpy, olctx);
807 XDestroyWindow(dpy, olwin);
812 glXDestroyContext(dpy, ctx);
817 XDestroyWindow(dpy, win);
829 glXDestroyContext(dpy, olctx);
834 XDestroyWindow(dpy, olwin);
839 glXDestroyContext(dpy, ctx);
844 XDestroyWindow(dpy, win);