10 #include <X11/Xutil.h>
11 #include <X11/keysym.h>
12 #include <X11/extensions/XShm.h>
16 enum { QUIT = 1, REDRAW = 2 };
18 static Window create_win(int width, int height, int bpp);
19 static void handle_event(XEvent *ev);
20 static int translate_keysym(KeySym sym);
21 static int parse_args(int argc, char **argv);
22 static void sig(int s);
24 static int win_width, win_height;
26 static unsigned int pending;
28 static Window win, root;
31 static Atom xa_wm_proto, xa_wm_delwin;
35 static XShmSegmentInfo shm;
36 static int wait_putimg;
37 static int xshm_ev_completion;
40 int main(int argc, char **argv)
44 struct timeval tv, tv0;
47 if((env = getenv("RBENCH_NO_WM"))) {
56 shm.shmaddr = (void*)-1;
60 read_config("rbench.cfg");
62 if(parse_args(argc, argv) == -1) {
66 if(!(dpy = XOpenDisplay(0))) {
67 fprintf(stderr, "failed to connect to the X server\n");
70 root = DefaultRootWindow(dpy);
71 xa_wm_proto = XInternAtom(dpy, "WM_PROTOCOLS", 0);
72 xa_wm_delwin = XInternAtom(dpy, "WM_DELETE_WINDOW", 0);
74 if(!XShmQueryExtension(dpy)) {
75 fprintf(stderr, "X shared memory extension is not available\n");
79 xshm_ev_completion = XShmGetEventBase(dpy) + ShmCompletion;
81 if(!(win = create_win(opt.width, opt.height, opt.bpp))) {
84 gc = XCreateGC(dpy, win, 0, 0);
86 if(!(ximg = XShmCreateImage(dpy, vis, opt.bpp, ZPixmap, 0, &shm, opt.width, opt.height))) {
87 fprintf(stderr, "failed to create shared memory image\n");
90 if((shm.shmid = shmget(IPC_PRIVATE, ximg->bytes_per_line * ximg->height, IPC_CREAT | 0777)) == -1) {
91 fprintf(stderr, "failed to create shared memory block\n");
94 if((shm.shmaddr = ximg->data = shmat(shm.shmid, 0, 0)) == (void*)-1) {
95 fprintf(stderr, "failed to attach shared memory block\n");
99 if(!XShmAttach(dpy, &shm)) {
100 fprintf(stderr, "XShmAttach failed");
104 fb_width = opt.width;
105 fb_height = opt.height;
107 fb_bpp = ximg->bytes_per_line < fb_width * 4 ? 24 : 32;
111 framebuf = ximg->data;
112 fb_pitch = ximg->bytes_per_line;
113 fb_rmask = ximg->red_mask;
114 fb_gmask = ximg->green_mask;
115 fb_bmask = ximg->blue_mask;
116 fb_rshift = mask_to_shift(fb_rmask);
117 fb_gshift = mask_to_shift(fb_gmask);
118 fb_bshift = mask_to_shift(fb_bmask);
124 gettimeofday(&tv0, 0);
126 while(!(pending & QUIT)) {
127 if(mapped) {/* && !wait_putimg) { */
128 while(XPending(dpy)) {
129 XNextEvent(dpy, &ev);
131 if(pending & QUIT) goto end;
135 gettimeofday(&tv, 0);
136 time_msec = (tv.tv_sec - tv0.tv_sec) * 1000 + (tv.tv_usec - tv0.tv_usec) / 1000;
141 XShmPutImage(dpy, win, gc, ximg, 0, 0, 0, 0, ximg->width, ximg->height, False);
146 XNextEvent(dpy, &ev);
148 if(pending & QUIT) goto end;
155 XShmDetach(dpy, &shm);
157 if(shm.shmaddr != (void*)-1) {
160 if(shm.shmid != -1) {
161 shmctl(shm.shmid, IPC_RMID, 0);
166 XDestroyWindow(dpy, win);
171 printf("avg framerate: %.1f fps\n", (10000 * num_frames / time_msec) / 10.0f);
176 static Window create_win(int width, int height, int bpp)
180 XVisualInfo *vinf, vtmpl;
181 unsigned int vinf_mask;
182 XSetWindowAttributes xattr;
183 XTextProperty txname;
185 const char *name = "retrobench X11";
187 scr = DefaultScreen(dpy);
191 vtmpl.class = bpp <= 8 ? PseudoColor : TrueColor;
192 vinf_mask = VisualScreenMask | VisualDepthMask | VisualClassMask;
193 if(!(vinf = XGetVisualInfo(dpy, vinf_mask, &vtmpl, &num_vis))) {
194 fprintf(stderr, "failed to find appropriate visual for %d bpp\n", bpp);
199 if(!(cmap = XCreateColormap(dpy, root, vis, bpp <= 8 ? AllocAll : AllocNone))) {
200 fprintf(stderr, "failed to allocate colormap\n");
204 xattr.background_pixel = BlackPixel(dpy, scr);
205 xattr.colormap = cmap;
206 xattr.override_redirect = no_wm ? True : False;
207 win = XCreateWindow(dpy, root, 0, 0, width, height, 0, vinf->depth,
208 InputOutput, vis, CWColormap | CWBackPixel | CWOverrideRedirect, &xattr);
211 XSelectInput(dpy, win, StructureNotifyMask | ExposureMask | KeyPressMask |
214 XStringListToTextProperty((char**)&name, 1, &txname);
215 XSetWMName(dpy, win, &txname);
216 XSetWMIconName(dpy, win, &txname);
219 XSetWMProtocols(dpy, win, &xa_wm_delwin, 1);
221 XMapWindow(dpy, win);
225 static void handle_event(XEvent *ev)
243 case ConfigureNotify:
244 if(ev->xconfigure.width != win_width || ev->xconfigure.height != win_height) {
245 win_width = ev->xconfigure.width;
246 win_height = ev->xconfigure.height;
253 if((sym = XKeycodeToKeysym(dpy, ev->xkey.keycode, 0))) {
254 if(sym == XK_Escape) {
258 if((key = translate_keysym(sym))) {
259 key_event(key, ev->xkey.type == KeyPress);
265 if(ev->xclient.message_type == xa_wm_proto) {
266 if(ev->xclient.data.l[0] == xa_wm_delwin) {
273 if(ev->type == xshm_ev_completion) {
280 static int translate_keysym(KeySym sym)
282 if(sym < 128) return sym;
294 static const char *usage_str =
295 "Usage: %s [options]\n"
297 " -s <WxH>: resolution\n"
298 " -b <bpp>: color depth\n"
299 " -h: print usage and exit\n";
301 static int parse_args(int argc, char **argv)
305 for(i=1; i<argc; i++) {
306 if(argv[i][0] == '-') {
312 if(!argv[++i] || sscanf(argv[i], "%dx%d", &opt.width, &opt.height) != 2) {
313 fprintf(stderr, "-s must be followed by WxH\n");
319 if(!argv[++i] || !(opt.bpp = atoi(argv[i]))) {
320 fprintf(stderr, "-b must be followed by the color depth\n");
326 printf(usage_str, argv[0]);
333 inval_arg: fprintf(stderr, "invalid argument: %s\n", argv[i]);
340 static void sig(int s)