1 /* 2 * DRM based vblank test program 3 * Copyright 2008 Tungsten Graphics 4 * Jakob Bornecrantz <jakob (at) tungstengraphics.com> 5 * Copyright 2008 Intel Corporation 6 * Jesse Barnes <jesse.barnes (at) intel.com> 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included in 16 * all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 24 * IN THE SOFTWARE. 25 */ 26 27 #ifdef HAVE_CONFIG_H 28 #include "config.h" 29 #endif 30 31 #include <assert.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <stdint.h> 35 #include <unistd.h> 36 #include <string.h> 37 #include <errno.h> 38 #include <sys/poll.h> 39 #include <sys/time.h> 40 41 #include "xf86drm.h" 42 #include "xf86drmMode.h" 43 44 #include "util/common.h" 45 #include "util/kms.h" 46 47 extern char *optarg; 48 extern int optind, opterr, optopt; 49 static char optstr[] = "D:M:s"; 50 51 int secondary = 0; 52 53 struct vbl_info { 54 unsigned int vbl_count; 55 struct timeval start; 56 }; 57 58 static void vblank_handler(int fd, unsigned int frame, unsigned int sec, 59 unsigned int usec, void *data) 60 { 61 drmVBlank vbl; 62 struct timeval end; 63 struct vbl_info *info = data; 64 double t; 65 66 vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; 67 if (secondary) 68 vbl.request.type |= DRM_VBLANK_SECONDARY; 69 vbl.request.sequence = 1; 70 vbl.request.signal = (unsigned long)data; 71 72 drmWaitVBlank(fd, &vbl); 73 74 info->vbl_count++; 75 76 if (info->vbl_count == 60) { 77 gettimeofday(&end, NULL); 78 t = end.tv_sec + end.tv_usec * 1e-6 - 79 (info->start.tv_sec + info->start.tv_usec * 1e-6); 80 fprintf(stderr, "freq: %.02fHz\n", info->vbl_count / t); 81 info->vbl_count = 0; 82 info->start = end; 83 } 84 } 85 86 static void usage(char *name) 87 { 88 fprintf(stderr, "usage: %s [-DMs]\n", name); 89 fprintf(stderr, "\n"); 90 fprintf(stderr, "options:\n"); 91 fprintf(stderr, " -D DEVICE open the given device\n"); 92 fprintf(stderr, " -M MODULE open the given module\n"); 93 fprintf(stderr, " -s use secondary pipe\n"); 94 exit(0); 95 } 96 97 int main(int argc, char **argv) 98 { 99 const char *device = NULL, *module = NULL; 100 int c, fd, ret; 101 drmVBlank vbl; 102 drmEventContext evctx; 103 struct vbl_info handler_info; 104 105 opterr = 0; 106 while ((c = getopt(argc, argv, optstr)) != -1) { 107 switch (c) { 108 case 'D': 109 device = optarg; 110 break; 111 case 'M': 112 module = optarg; 113 break; 114 case 's': 115 secondary = 1; 116 break; 117 default: 118 usage(argv[0]); 119 break; 120 } 121 } 122 123 fd = util_open(module, device); 124 if (fd < 0) 125 return 1; 126 127 /* Get current count first */ 128 vbl.request.type = DRM_VBLANK_RELATIVE; 129 if (secondary) 130 vbl.request.type |= DRM_VBLANK_SECONDARY; 131 vbl.request.sequence = 0; 132 ret = drmWaitVBlank(fd, &vbl); 133 if (ret != 0) { 134 printf("drmWaitVBlank (relative) failed ret: %i\n", ret); 135 return -1; 136 } 137 138 printf("starting count: %d\n", vbl.request.sequence); 139 140 handler_info.vbl_count = 0; 141 gettimeofday(&handler_info.start, NULL); 142 143 /* Queue an event for frame + 1 */ 144 vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; 145 if (secondary) 146 vbl.request.type |= DRM_VBLANK_SECONDARY; 147 vbl.request.sequence = 1; 148 vbl.request.signal = (unsigned long)&handler_info; 149 ret = drmWaitVBlank(fd, &vbl); 150 if (ret != 0) { 151 printf("drmWaitVBlank (relative, event) failed ret: %i\n", ret); 152 return -1; 153 } 154 155 /* Set up our event handler */ 156 memset(&evctx, 0, sizeof evctx); 157 evctx.version = DRM_EVENT_CONTEXT_VERSION; 158 evctx.vblank_handler = vblank_handler; 159 evctx.page_flip_handler = NULL; 160 161 /* Poll for events */ 162 while (1) { 163 struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; 164 fd_set fds; 165 166 FD_ZERO(&fds); 167 FD_SET(0, &fds); 168 FD_SET(fd, &fds); 169 ret = select(fd + 1, &fds, NULL, NULL, &timeout); 170 171 if (ret <= 0) { 172 fprintf(stderr, "select timed out or error (ret %d)\n", 173 ret); 174 continue; 175 } else if (FD_ISSET(0, &fds)) { 176 break; 177 } 178 179 ret = drmHandleEvent(fd, &evctx); 180 if (ret != 0) { 181 printf("drmHandleEvent failed: %i\n", ret); 182 return -1; 183 } 184 } 185 186 return 0; 187 } 188