diff options
author | Simon Rettberg | 2018-10-16 10:08:48 +0200 |
---|---|---|
committer | Simon Rettberg | 2018-10-16 10:08:48 +0200 |
commit | d3a98cf6cbc3bd0b9efc570f58e8812c03931c18 (patch) | |
tree | cbddf8e50f35a9c6e878a5bfe3c6d625d99e12ba /hacks/fps.c | |
download | xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.gz xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.xz xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.zip |
Original 5.40
Diffstat (limited to 'hacks/fps.c')
-rw-r--r-- | hacks/fps.c | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/hacks/fps.c b/hacks/fps.c new file mode 100644 index 0000000..a24f623 --- /dev/null +++ b/hacks/fps.c @@ -0,0 +1,268 @@ +/* fps, Copyright (c) 2001-2018 Jamie Zawinski <jwz@jwz.org> + * Draw a frames-per-second display (Xlib and OpenGL). + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <time.h> +#include "screenhackI.h" +#include "fpsI.h" + +fps_state * +fps_init (Display *dpy, Window window) +{ + fps_state *st; + const char *font; + XFontStruct *f; + Bool top_p; + XWindowAttributes xgwa; + + if (! get_boolean_resource (dpy, "doFPS", "DoFPS")) + return 0; + + if (!strcasecmp (progname, "BSOD")) return 0; /* Never worked right */ + + top_p = get_boolean_resource (dpy, "fpsTop", "FPSTop"); + + st = (fps_state *) calloc (1, sizeof(*st)); + + st->dpy = dpy; + st->window = window; + st->clear_p = get_boolean_resource (dpy, "fpsSolid", "FPSSolid"); + + font = get_string_resource (dpy, "fpsFont", "Font"); + + if (!font) + font = "-*-courier-bold-r-normal-*-*-180-*-*-*-*-*-*"; /* also texfont.c */ + f = load_font_retry (dpy, font); + if (!f) abort(); + + { + XGCValues gcv; + XGetWindowAttributes (dpy, window, &xgwa); + gcv.font = f->fid; + gcv.foreground = + get_pixel_resource (st->dpy, xgwa.colormap, "foreground", "Foreground"); + st->draw_gc = XCreateGC (dpy, window, GCFont|GCForeground, &gcv); + gcv.foreground = + get_pixel_resource (st->dpy, xgwa.colormap, "background", "Background"); + st->erase_gc = XCreateGC (dpy, window, GCFont|GCForeground, &gcv); + } + + st->font = f; + st->x = 10; + st->y = 10; + if (top_p) + st->y = - (st->font->ascent + st->font->descent + 10); + +# ifdef USE_IPHONE + /* Don't hide the FPS display under the iPhone X bezel. + #### This is the worst of all possible ways to do this! But how else? + */ + if (xgwa.width == 2436 || xgwa.height == 2436) + { + st->x += 48; + st->y += 48 * (top_p ? -1 : 1); + } +# endif + + strcpy (st->string, "FPS: ... "); + + return st; +} + +void +fps_free (fps_state *st) +{ + if (st->draw_gc) XFreeGC (st->dpy, st->draw_gc); + if (st->erase_gc) XFreeGC (st->dpy, st->erase_gc); + if (st->font) XFreeFont (st->dpy, st->font); + free (st); +} + + +void +fps_slept (fps_state *st, unsigned long usecs) +{ + st->slept += usecs; +} + + +double +fps_compute (fps_state *st, unsigned long polys, double depth) +{ + if (! st) return 0; /* too early? */ + + /* Every N frames (where N is approximately one second's worth of frames) + check the wall clock. We do this because checking the wall clock is + a slow operation. + */ + if (st->frame_count++ >= st->last_ifps) + { +# ifdef GETTIMEOFDAY_TWO_ARGS + struct timezone tzp; + gettimeofday(&st->this_frame_end, &tzp); +# else + gettimeofday(&st->this_frame_end); +# endif + + if (st->prev_frame_end.tv_sec == 0) + st->prev_frame_end = st->this_frame_end; + } + + /* If we've probed the wall-clock time, regenerate the string. + */ + if (st->this_frame_end.tv_sec != st->prev_frame_end.tv_sec) + { + double uprev_frame_end = (st->prev_frame_end.tv_sec + + ((double) st->prev_frame_end.tv_usec + * 0.000001)); + double uthis_frame_end = (st->this_frame_end.tv_sec + + ((double) st->this_frame_end.tv_usec + * 0.000001)); + double fps = st->frame_count / (uthis_frame_end - uprev_frame_end); + double idle = (((double) st->slept * 0.000001) / + (uthis_frame_end - uprev_frame_end)); + double load = 100 * (1 - idle); + + if (load < 0) load = 0; /* well that's obviously nonsense... */ + + st->prev_frame_end = st->this_frame_end; + st->frame_count = 0; + st->slept = 0; + st->last_ifps = fps; + st->last_fps = fps; + + sprintf (st->string, (polys + ? "FPS: %.1f \nLoad: %.1f%% " + : "FPS: %.1f \nLoad: %.1f%% "), + fps, load); + + if (polys > 0) + { + const char *s = ""; +# if 0 + if (polys >= (1024 * 1024)) polys >>= 20, s = "M"; + else if (polys >= 2048) polys >>= 10, s = "K"; +# endif + + strcat (st->string, "\nPolys: "); + if (polys >= 1000000) + sprintf (st->string + strlen(st->string), "%lu,%03lu,%03lu%s ", + (polys / 1000000), ((polys / 1000) % 1000), + (polys % 1000), s); + else if (polys >= 1000) + sprintf (st->string + strlen(st->string), "%lu,%03lu%s ", + (polys / 1000), (polys % 1000), s); + else + sprintf (st->string + strlen(st->string), "%lu%s ", polys, s); + } + + if (depth >= 0.0) + { + unsigned long L = strlen (st->string); + char *s = st->string + L; + strcat (s, "\nDepth: "); + sprintf (s + strlen(s), "%.1f", depth); + L = strlen (s); + /* Remove trailing ".0" in case depth is not a fraction. */ + if (s[L-2] == '.' && s[L-1] == '0') + s[L-2] = 0; + } + } + + return st->last_fps; +} + + + +/* Width (and optionally height) of the string in pixels. + */ +static int +string_width (XFontStruct *f, const char *c, int *height_ret) +{ + int x = 0; + int max_w = 0; + int h = f->ascent + f->descent; + while (*c) + { + int cc = *((unsigned char *) c); + if (*c == '\n') + { + if (x > max_w) max_w = x; + x = 0; + h += f->ascent + f->descent; + } + else + x += (f->per_char + ? f->per_char[cc-f->min_char_or_byte2].width + : f->min_bounds.rbearing); + c++; + } + if (x > max_w) max_w = x; + if (height_ret) *height_ret = h; + + return max_w; +} + + +/* This function is used only in Xlib mode. For GL mode, see glx/fps-gl.c. + */ +void +fps_draw (fps_state *st) +{ + XWindowAttributes xgwa; + const char *string = st->string; + const char *s; + int x = st->x; + int y = st->y; + int lines = 1; + int lh = st->font->ascent + st->font->descent; + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + + for (s = string; *s; s++) + if (*s == '\n') lines++; + + if (y < 0) + y = -y + (lines-1) * lh; + else + y = xgwa.height - y; + + y -= lh * (lines-1) + st->font->descent; + + /* clear the background */ + if (st->clear_p) + { + int w, h; + w = string_width (st->font, string, &h); + XFillRectangle (st->dpy, st->window, st->erase_gc, + x - st->font->descent, + y - lh, + w + 2*st->font->descent, + h + 2*st->font->descent); + } + + /* draw the text */ + while (lines) + { + s = strchr (string, '\n'); + if (! s) s = string + strlen(string); + XDrawString (st->dpy, st->window, st->draw_gc, + x, y, string, (int) (s - string)); + string = s; + string++; + lines--; + y += lh; + } +} |