1 /* 2 * DRM based mode setting 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 /* 28 * This fairly simple test program dumps output in a similar format to the 29 * "xrandr" tool everyone knows & loves. It's necessarily slightly different 30 * since the kernel separates outputs into encoder and connector structures, 31 * each with their own unique ID. The program also allows test testing of the 32 * memory management and mode setting APIs by allowing the user to specify a 33 * connector and mode to use for mode setting. If all works as expected, a 34 * blue background should be painted on the monitor attached to the specified 35 * connector after the selected mode is set. 36 * 37 * TODO: use cairo to write the mode info on the selected output once 38 * the mode has been programmed, along with possible test patterns. 39 */ 40 #ifdef HAVE_CONFIG_H 41 #include "config.h" 42 #endif 43 44 #include <assert.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <stdint.h> 48 #include <unistd.h> 49 #include <string.h> 50 #include <errno.h> 51 #include <sys/poll.h> 52 #include <sys/time.h> 53 54 #include "xf86drm.h" 55 #include "xf86drmMode.h" 56 57 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 58 59 extern char *optarg; 60 extern int optind, opterr, optopt; 61 static char optstr[] = "s"; 62 63 int secondary = 0; 64 65 struct vbl_info { 66 unsigned int vbl_count; 67 struct timeval start; 68 }; 69 70 static void vblank_handler(int fd, unsigned int frame, unsigned int sec, 71 unsigned int usec, void *data) 72 { 73 drmVBlank vbl; 74 struct timeval end; 75 struct vbl_info *info = data; 76 double t; 77 78 vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; 79 if (secondary) 80 vbl.request.type |= DRM_VBLANK_SECONDARY; 81 vbl.request.sequence = 1; 82 vbl.request.signal = (unsigned long)data; 83 84 drmWaitVBlank(fd, &vbl); 85 86 info->vbl_count++; 87 88 if (info->vbl_count == 60) { 89 gettimeofday(&end, NULL); 90 t = end.tv_sec + end.tv_usec * 1e-6 - 91 (info->start.tv_sec + info->start.tv_usec * 1e-6); 92 fprintf(stderr, "freq: %.02fHz\n", info->vbl_count / t); 93 info->vbl_count = 0; 94 info->start = end; 95 } 96 } 97 98 static void usage(char *name) 99 { 100 fprintf(stderr, "usage: %s [-s]\n", name); 101 fprintf(stderr, "\t-s\tuse secondary pipe\n"); 102 exit(0); 103 } 104 105 int main(int argc, char **argv) 106 { 107 int i, c, fd, ret; 108 char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "exynos", "omapdrm", "tilcdc", "msm", "tegra" }; 109 drmVBlank vbl; 110 drmEventContext evctx; 111 struct vbl_info handler_info; 112 113 opterr = 0; 114 while ((c = getopt(argc, argv, optstr)) != -1) { 115 switch (c) { 116 case 's': 117 secondary = 1; 118 break; 119 default: 120 usage(argv[0]); 121 break; 122 } 123 } 124 125 for (i = 0; i < ARRAY_SIZE(modules); i++) { 126 printf("trying to load module %s...", modules[i]); 127 fd = drmOpen(modules[i], NULL); 128 if (fd < 0) { 129 printf("failed.\n"); 130 } else { 131 printf("success.\n"); 132 break; 133 } 134 } 135 136 if (i == ARRAY_SIZE(modules)) { 137 fprintf(stderr, "failed to load any modules, aborting.\n"); 138 return -1; 139 } 140 141 /* Get current count first */ 142 vbl.request.type = DRM_VBLANK_RELATIVE; 143 if (secondary) 144 vbl.request.type |= DRM_VBLANK_SECONDARY; 145 vbl.request.sequence = 0; 146 ret = drmWaitVBlank(fd, &vbl); 147 if (ret != 0) { 148 printf("drmWaitVBlank (relative) failed ret: %i\n", ret); 149 return -1; 150 } 151 152 printf("starting count: %d\n", vbl.request.sequence); 153 154 handler_info.vbl_count = 0; 155 gettimeofday(&handler_info.start, NULL); 156 157 /* Queue an event for frame + 1 */ 158 vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; 159 if (secondary) 160 vbl.request.type |= DRM_VBLANK_SECONDARY; 161 vbl.request.sequence = 1; 162 vbl.request.signal = (unsigned long)&handler_info; 163 ret = drmWaitVBlank(fd, &vbl); 164 if (ret != 0) { 165 printf("drmWaitVBlank (relative, event) failed ret: %i\n", ret); 166 return -1; 167 } 168 169 /* Set up our event handler */ 170 memset(&evctx, 0, sizeof evctx); 171 evctx.version = DRM_EVENT_CONTEXT_VERSION; 172 evctx.vblank_handler = vblank_handler; 173 evctx.page_flip_handler = NULL; 174 175 /* Poll for events */ 176 while (1) { 177 struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; 178 fd_set fds; 179 int ret; 180 181 FD_ZERO(&fds); 182 FD_SET(0, &fds); 183 FD_SET(fd, &fds); 184 ret = select(fd + 1, &fds, NULL, NULL, &timeout); 185 186 if (ret <= 0) { 187 fprintf(stderr, "select timed out or error (ret %d)\n", 188 ret); 189 continue; 190 } else if (FD_ISSET(0, &fds)) { 191 break; 192 } 193 194 ret = drmHandleEvent(fd, &evctx); 195 if (ret != 0) { 196 printf("drmHandleEvent failed: %i\n", ret); 197 return -1; 198 } 199 } 200 201 return 0; 202 } 203