1 /* tube, Copyright (c) 2001 Jamie Zawinski <jwz@jwz.org>
2 * Utility function to draw a frames-per-second display.
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
17 #include "screenhack.h"
18 #include "xlockmoreI.h"
24 #undef DEBUG /* Defining this causes check_gl_error() to be called inside
25 time-critical sections, which could slow things down (since
26 it might result in a round-trip, and stall of the pipeline.)
29 extern void clear_gl_error (void);
30 extern void check_gl_error (const char *type);
32 static int fps_text_x = 10;
33 static int fps_text_y = 10;
34 static int fps_ascent, fps_descent;
35 static GLuint font_dlist;
36 static Bool fps_clear_p = False;
39 fps_init (ModeInfo *mi)
41 const char *font = get_string_resource ("fpsFont", "Font");
46 fps_clear_p = get_boolean_resource ("fpsSolid", "FPSSolid");
48 if (!font) font = "-*-courier-bold-r-normal-*-180-*";
49 f = XLoadQueryFont(mi->dpy, font);
50 if (!f) f = XLoadQueryFont(mi->dpy, "fixed");
53 first = f->min_char_or_byte2;
54 last = f->max_char_or_byte2;
57 font_dlist = glGenLists ((GLuint) last+1);
58 check_gl_error ("glGenLists");
60 fps_ascent = f->ascent;
61 fps_descent = f->descent;
63 if (get_boolean_resource ("fpsTop", "FPSTop"))
64 fps_text_y = - (f->ascent + 10);
66 glXUseXFont(id, first, last-first+1, font_dlist + first);
67 check_gl_error ("glXUseXFont");
72 fps_print_string (ModeInfo *mi, GLfloat x, GLfloat y, const char *string)
74 const char *L2 = strchr (string, '\n');
78 y = mi->xgwa.height + y;
80 y -= (fps_ascent + fps_descent);
87 /* Sadly, this causes a stall of the graphics pipeline (as would the
88 equivalent calls to glGet*.) But there's no way around this, short
89 of having each caller set up the specific display matrix we need
90 here, which would kind of defeat the purpose of centralizing this
93 glPushAttrib(GL_TRANSFORM_BIT | /* for matrix contents */
94 GL_ENABLE_BIT | /* for various glDisable calls */
95 GL_CURRENT_BIT | /* for glColor3f() */
96 GL_LIST_BIT); /* for glListBase() */
99 check_gl_error ("glPushAttrib");
102 /* disable lighting and texturing when drawing bitmaps!
103 (glPopAttrib() restores these, I believe.)
105 glDisable(GL_TEXTURE_2D);
106 glDisable(GL_LIGHTING);
108 glDisable(GL_DEPTH_TEST);
110 /* glPopAttrib() does not restore matrix changes, so we must
111 push/pop the matrix stacks to be non-intrusive there.
113 glMatrixMode(GL_PROJECTION);
117 check_gl_error ("glPushMatrix");
121 /* Each matrix mode has its own stack, so we need to push/pop
123 glMatrixMode(GL_MODELVIEW);
127 check_gl_error ("glPushMatrix");
131 gluOrtho2D(0, mi->xgwa.width, 0, mi->xgwa.height);
133 check_gl_error ("gluOrtho2D");
136 /* clear the background */
139 int lines = L2 ? 2 : 1;
141 glRecti (x / 2, y - fps_descent,
143 y + lines * (fps_ascent + fps_descent));
148 glRasterPos2f (x, y);
149 glListBase (font_dlist);
154 glCallLists (strlen(L2), GL_UNSIGNED_BYTE, L2);
155 glRasterPos2f (x, y + (fps_ascent + fps_descent));
156 glCallLists (L2 - string - 1, GL_UNSIGNED_BYTE, string);
160 glCallLists (strlen(string), GL_UNSIGNED_BYTE, string);
164 check_gl_error ("fps_print_string");
169 glMatrixMode(GL_PROJECTION);
173 /* clean up after our state changes */
176 check_gl_error ("glPopAttrib");
182 do_fps (ModeInfo *mi)
184 static Bool initted_p = False;
185 static int last_ifps = 0;
186 static int frame_count = 0;
187 static struct timeval prev = { 0, };
188 static struct timeval now = { 0, };
189 static char msg [1024] = { 0, };
195 strcpy (msg, "FPS: (accumulating...)");
198 /* Every N frames (where N is approximately one second's worth of frames)
199 check the wall clock. We do this because checking the wall clock is
202 if (frame_count++ >= last_ifps)
204 # ifdef GETTIMEOFDAY_TWO_ARGS
206 gettimeofday(&now, &tzp);
211 if (prev.tv_sec == 0)
215 /* If we've probed the wall-clock time, regenerate the string.
217 if (now.tv_sec != prev.tv_sec)
219 double uprev = prev.tv_sec + ((double) prev.tv_usec * 0.000001);
220 double unow = now.tv_sec + ((double) now.tv_usec * 0.000001);
221 double fps = frame_count / (unow - uprev);
227 sprintf (msg, "FPS: %.02f", fps);
232 sprintf(buf, "%f", mi->pause / 1000000.0); /* FTSO C */
233 while(*buf && buf[strlen(buf)-1] == '0')
234 buf[strlen(buf)-1] = 0;
235 if (buf[strlen(buf)-1] == '.')
236 buf[strlen(buf)-1] = 0;
237 sprintf(msg + strlen(msg), " (including %s sec/frame delay)",
241 if (mi->polygon_count > 0)
243 unsigned long p = mi->polygon_count;
246 if (p >= (1024 * 1024)) p >>= 20, s = "M";
247 else if (p >= 2048) p >>= 10, s = "K";
250 strcat (msg, "\nPolys: ");
252 sprintf (msg + strlen(msg), "%lu,%03lu,%03lu%s",
253 (p / 1000000), ((p / 1000) % 1000), (p % 1000), s);
255 sprintf (msg + strlen(msg), "%lu,%03lu%s",
256 (p / 1000), (p % 1000), s);
258 sprintf (msg + strlen(msg), "%lu%s", p, s);
262 /* Print the string every frame (or else nothing will show up.)
264 fps_print_string (mi, fps_text_x, fps_text_y, msg);