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)
75 y = mi->xgwa.height + y;
81 /* Sadly, this causes a stall of the graphics pipeline (as would the
82 equivalent calls to glGet*.) But there's no way around this, short
83 of having each caller set up the specific display matrix we need
84 here, which would kind of defeat the purpose of centralizing this
87 glPushAttrib(GL_TRANSFORM_BIT | /* for matrix contents */
88 GL_ENABLE_BIT | /* for various glDisable calls */
89 GL_CURRENT_BIT | /* for glColor3f() */
90 GL_LIST_BIT); /* for glListBase() */
93 check_gl_error ("glPushAttrib");
96 /* disable lighting and texturing when drawing bitmaps!
97 (glPopAttrib() restores these, I believe.)
99 glDisable(GL_TEXTURE_2D);
100 glDisable(GL_LIGHTING);
102 glDisable(GL_DEPTH_TEST);
104 /* glPopAttrib() does not restore matrix changes, so we must
105 push/pop the matrix stacks to be non-intrusive there.
107 glMatrixMode(GL_PROJECTION);
111 check_gl_error ("glPushMatrix");
115 /* Each matrix mode has its own stack, so we need to push/pop
117 glMatrixMode(GL_MODELVIEW);
121 check_gl_error ("glPushMatrix");
125 gluOrtho2D(0, mi->xgwa.width, 0, mi->xgwa.height);
127 check_gl_error ("gluOrtho2D");
130 /* clear the background */
134 glRecti (x / 2, y - fps_descent,
136 y + fps_ascent + fps_descent);
141 glRasterPos2f (x, y);
142 glListBase (font_dlist);
143 glCallLists (strlen(string), GL_UNSIGNED_BYTE, string);
146 check_gl_error ("fps_print_string");
151 glMatrixMode(GL_PROJECTION);
155 /* clean up after our state changes */
158 check_gl_error ("glPopAttrib");
164 do_fps (ModeInfo *mi)
166 static Bool initted_p = False;
167 static int last_ifps = 0;
168 static int frame_count = 0;
169 static struct timeval prev = { 0, };
170 static struct timeval now = { 0, };
171 static char msg [1024] = { 0, };
177 strcpy (msg, "FPS: (accumulating...)");
180 /* Every N frames (where N is approximately one second's worth of frames)
181 check the wall clock. We do this because checking the wall clock is
184 if (frame_count++ >= last_ifps)
186 # ifdef GETTIMEOFDAY_TWO_ARGS
188 gettimeofday(&now, &tzp);
193 if (prev.tv_sec == 0)
197 /* If we've probed the wall-clock time, regenerate the string.
199 if (now.tv_sec != prev.tv_sec)
201 double uprev = prev.tv_sec + ((double) prev.tv_usec * 0.000001);
202 double unow = now.tv_sec + ((double) now.tv_usec * 0.000001);
203 double fps = frame_count / (unow - uprev);
209 sprintf (msg, "FPS: %.02f", fps);
214 sprintf(buf, "%f", mi->pause / 1000000.0); /* FTSO C */
215 while(*buf && buf[strlen(buf)-1] == '0')
216 buf[strlen(buf)-1] = 0;
217 if (buf[strlen(buf)-1] == '.')
218 buf[strlen(buf)-1] = 0;
219 sprintf(msg + strlen(msg), " (including %s sec/frame delay)",
224 /* Print the string every frame (or else nothing will show up.)
226 fps_print_string (mi, fps_text_x, fps_text_y, msg);