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 #include <assert.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <stdint.h> 31 #include <unistd.h> 32 #include <string.h> 33 #include <errno.h> 34 #include <poll.h> 35 #include <sys/time.h> 36 #ifdef HAVE_SYS_SELECT_H 37 #include <sys/select.h> 38 #endif 39 40 #include "xf86drm.h" 41 #include "xf86drmMode.h" 42 43 #include "util/common.h" 44 #include "util/kms.h" 45 46 extern char *optarg; 47 extern int optind, opterr, optopt; 48 static char optstr[] = "D:M:s"; 49 50 int secondary = 0; 51 52 struct vbl_info { 53 unsigned int vbl_count; 54 struct timeval start; 55 }; 56 57 static void vblank_handler(int fd, unsigned int frame, unsigned int sec, 58 unsigned int usec, void *data) 59 { 60 drmVBlank vbl; 61 struct timeval end; 62 struct vbl_info *info = data; 63 double t; 64 65 vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; 66 if (secondary) 67 vbl.request.type |= DRM_VBLANK_SECONDARY; 68 vbl.request.sequence = 1; 69 vbl.request.signal = (unsigned long)data; 70 71 drmWaitVBlank(fd, &vbl); 72 73 info->vbl_count++; 74 75 if (info->vbl_count == 60) { 76 gettimeofday(&end, NULL); 77 t = end.tv_sec + end.tv_usec * 1e-6 - 78 (info->start.tv_sec + info->start.tv_usec * 1e-6); 79 fprintf(stderr, "freq: %.02fHz\n", info->vbl_count / t); 80 info->vbl_count = 0; 81 info->start = end; 82 } 83 } 84 85 static void usage(char *name) 86 { 87 fprintf(stderr, "usage: %s [-DMs]\n", name); 88 fprintf(stderr, "\n"); 89 fprintf(stderr, "options:\n"); 90 fprintf(stderr, " -D DEVICE open the given device\n"); 91 fprintf(stderr, " -M MODULE open the given module\n"); 92 fprintf(stderr, " -s use secondary pipe\n"); 93 exit(0); 94 } 95 96 int main(int argc, char **argv) 97 { 98 const char *device = NULL, *module = NULL; 99 int c, fd, ret; 100 drmVBlank vbl; 101 drmEventContext evctx; 102 struct vbl_info handler_info; 103 104 opterr = 0; 105 while ((c = getopt(argc, argv, optstr)) != -1) { 106 switch (c) { 107 case 'D': 108 device = optarg; 109 break; 110 case 'M': 111 module = optarg; 112 break; 113 case 's': 114 secondary = 1; 115 break; 116 default: 117 usage(argv[0]); 118 break; 119 } 120 } 121 122 fd = util_open(device, module); 123 if (fd < 0) 124 return 1; 125 126 /* Get current count first */ 127 vbl.request.type = DRM_VBLANK_RELATIVE; 128 if (secondary) 129 vbl.request.type |= DRM_VBLANK_SECONDARY; 130 vbl.request.sequence = 0; 131 ret = drmWaitVBlank(fd, &vbl); 132 if (ret != 0) { 133 printf("drmWaitVBlank (relative) failed ret: %i\n", ret); 134 return -1; 135 } 136 137 printf("starting count: %d\n", vbl.request.sequence); 138 139 handler_info.vbl_count = 0; 140 gettimeofday(&handler_info.start, NULL); 141 142 /* Queue an event for frame + 1 */ 143 vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; 144 if (secondary) 145 vbl.request.type |= DRM_VBLANK_SECONDARY; 146 vbl.request.sequence = 1; 147 vbl.request.signal = (unsigned long)&handler_info; 148 ret = drmWaitVBlank(fd, &vbl); 149 if (ret != 0) { 150 printf("drmWaitVBlank (relative, event) failed ret: %i\n", ret); 151 return -1; 152 } 153 154 /* Set up our event handler */ 155 memset(&evctx, 0, sizeof evctx); 156 evctx.version = DRM_EVENT_CONTEXT_VERSION; 157 evctx.vblank_handler = vblank_handler; 158 evctx.page_flip_handler = NULL; 159 160 /* Poll for events */ 161 while (1) { 162 struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; 163 fd_set fds; 164 165 FD_ZERO(&fds); 166 FD_SET(0, &fds); 167 FD_SET(fd, &fds); 168 ret = select(fd + 1, &fds, NULL, NULL, &timeout); 169 170 if (ret <= 0) { 171 fprintf(stderr, "select timed out or error (ret %d)\n", 172 ret); 173 continue; 174 } else if (FD_ISSET(0, &fds)) { 175 break; 176 } 177 178 ret = drmHandleEvent(fd, &evctx); 179 if (ret != 0) { 180 printf("drmHandleEvent failed: %i\n", ret); 181 return -1; 182 } 183 } 184 185 return 0; 186 } 187