1 /* fps, Copyright (c) 2001-2011 Jamie Zawinski <jwz@jwz.org>
2 * Draw a frames-per-second display (Xlib and OpenGL).
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
15 #endif /* HAVE_CONFIG_H */
17 #include "screenhackI.h"
21 fps_init (Display *dpy, Window window)
27 if (! get_boolean_resource (dpy, "doFPS", "DoFPS"))
30 st = (fps_state *) calloc (1, sizeof(*st));
34 st->clear_p = get_boolean_resource (dpy, "fpsSolid", "FPSSolid");
36 font = get_string_resource (dpy, "fpsFont", "Font");
38 if (!font) font = "-*-courier-bold-r-normal-*-180-*";
39 f = XLoadQueryFont (dpy, font);
40 if (!f) f = XLoadQueryFont (dpy, "fixed");
43 XWindowAttributes xgwa;
45 XGetWindowAttributes (dpy, window, &xgwa);
48 get_pixel_resource (st->dpy, xgwa.colormap, "foreground", "Foreground");
49 st->draw_gc = XCreateGC (dpy, window, GCFont|GCForeground, &gcv);
51 get_pixel_resource (st->dpy, xgwa.colormap, "background", "Background");
52 st->erase_gc = XCreateGC (dpy, window, GCFont|GCForeground, &gcv);
58 if (get_boolean_resource (dpy, "fpsTop", "FPSTop"))
59 /* don't leave a blank line in GL top-fps. */
60 st->y = - (/*st->font->ascent +*/ st->font->descent + 10);
62 strcpy (st->string, "FPS: ... ");
68 fps_free (fps_state *st)
70 if (st->draw_gc) XFreeGC (st->dpy, st->draw_gc);
71 if (st->erase_gc) XFreeGC (st->dpy, st->erase_gc);
72 if (st->font) XFreeFont (st->dpy, st->font);
78 fps_slept (fps_state *st, unsigned long usecs)
85 fps_compute (fps_state *st, unsigned long polys, double depth)
87 if (! st) return 0; /* too early? */
89 /* Every N frames (where N is approximately one second's worth of frames)
90 check the wall clock. We do this because checking the wall clock is
93 if (st->frame_count++ >= st->last_ifps)
95 # ifdef GETTIMEOFDAY_TWO_ARGS
97 gettimeofday(&st->this_frame_end, &tzp);
99 gettimeofday(&st->this_frame_end);
102 if (st->prev_frame_end.tv_sec == 0)
103 st->prev_frame_end = st->this_frame_end;
106 /* If we've probed the wall-clock time, regenerate the string.
108 if (st->this_frame_end.tv_sec != st->prev_frame_end.tv_sec)
110 double uprev_frame_end = (st->prev_frame_end.tv_sec +
111 ((double) st->prev_frame_end.tv_usec
113 double uthis_frame_end = (st->this_frame_end.tv_sec +
114 ((double) st->this_frame_end.tv_usec
116 double fps = st->frame_count / (uthis_frame_end - uprev_frame_end);
117 double idle = (((double) st->slept * 0.000001) /
118 (uthis_frame_end - uprev_frame_end));
119 double load = 100 * (1 - idle);
121 if (load < 0) load = 0; /* well that's obviously nonsense... */
123 st->prev_frame_end = st->this_frame_end;
129 sprintf (st->string, (polys
130 ? "FPS: %.1f \nLoad: %.1f%% "
131 : "FPS: %.1f \nLoad: %.1f%% "),
138 if (polys >= (1024 * 1024)) polys >>= 20, s = "M";
139 else if (polys >= 2048) polys >>= 10, s = "K";
142 strcat (st->string, "\nPolys: ");
143 if (polys >= 1000000)
144 sprintf (st->string + strlen(st->string), "%lu,%03lu,%03lu%s ",
145 (polys / 1000000), ((polys / 1000) % 1000),
147 else if (polys >= 1000)
148 sprintf (st->string + strlen(st->string), "%lu,%03lu%s ",
149 (polys / 1000), (polys % 1000), s);
151 sprintf (st->string + strlen(st->string), "%lu%s ", polys, s);
156 unsigned long L = strlen (st->string);
157 char *s = st->string + L;
158 strcat (s, "\nDepth: ");
159 sprintf (s + strlen(s), "%.1f", depth);
161 /* Remove trailing ".0" in case depth is not a fraction. */
162 if (s[L-2] == '.' && s[L-1] == '0')
172 /* Width (and optionally height) of the string in pixels.
175 string_width (XFontStruct *f, const char *c, int *height_ret)
179 int h = f->ascent + f->descent;
182 int cc = *((unsigned char *) c);
185 if (x > max_w) max_w = x;
187 h += f->ascent + f->descent;
191 ? f->per_char[cc-f->min_char_or_byte2].width
192 : f->min_bounds.rbearing);
195 if (x > max_w) max_w = x;
196 if (height_ret) *height_ret = h;
202 /* This function is used only in Xlib mode. For GL mode, see glx/fps-gl.c.
205 fps_draw (fps_state *st)
207 XWindowAttributes xgwa;
208 const char *string = st->string;
213 int lh = st->font->ascent + st->font->descent;
215 XGetWindowAttributes (st->dpy, st->window, &xgwa);
217 for (s = string; *s; s++)
218 if (*s == '\n') lines++;
221 y = -y + (lines-1) * lh;
225 y -= lh * (lines-1) + st->font->descent;
227 /* clear the background */
231 w = string_width (st->font, string, &h);
232 XFillRectangle (st->dpy, st->window, st->erase_gc,
233 x - st->font->descent,
235 w + 2*st->font->descent,
236 h + 2*st->font->descent);
242 s = strchr (string, '\n');
243 if (! s) s = string + strlen(string);
244 XDrawString (st->dpy, st->window, st->draw_gc,
245 x, y, string, (int) (s - string));