| /* | |
| * DRM based vblank test program | |
| * Copyright 2008 Tungsten Graphics | |
| * Jakob Bornecrantz <jakob@tungstengraphics.com> | |
| * Copyright 2008 Intel Corporation | |
| * Jesse Barnes <jesse.barnes@intel.com> | |
| * | |
| * Permission is hereby granted, free of charge, to any person obtaining a | |
| * copy of this software and associated documentation files (the "Software"), | |
| * to deal in the Software without restriction, including without limitation | |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| * and/or sell copies of the Software, and to permit persons to whom the | |
| * Software is furnished to do so, subject to the following conditions: | |
| * | |
| * The above copyright notice and this permission notice shall be included in | |
| * all copies or substantial portions of the Software. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
| * IN THE SOFTWARE. | |
| */ | |
| #ifdef HAVE_CONFIG_H | |
| #include "config.h" | |
| #endif | |
| #include <assert.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <stdint.h> | |
| #include <unistd.h> | |
| #include <string.h> | |
| #include <errno.h> | |
| #include <poll.h> | |
| #include <sys/time.h> | |
| #ifdef HAVE_SYS_SELECT_H | |
| #include <sys/select.h> | |
| #endif | |
| #include "xf86drm.h" | |
| #include "xf86drmMode.h" | |
| #include "util/common.h" | |
| #include "util/kms.h" | |
| extern char *optarg; | |
| extern int optind, opterr, optopt; | |
| static char optstr[] = "D:M:s"; | |
| int secondary = 0; | |
| struct vbl_info { | |
| unsigned int vbl_count; | |
| struct timeval start; | |
| }; | |
| static void vblank_handler(int fd, unsigned int frame, unsigned int sec, | |
| unsigned int usec, void *data) | |
| { | |
| drmVBlank vbl; | |
| struct timeval end; | |
| struct vbl_info *info = data; | |
| double t; | |
| vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; | |
| if (secondary) | |
| vbl.request.type |= DRM_VBLANK_SECONDARY; | |
| vbl.request.sequence = 1; | |
| vbl.request.signal = (unsigned long)data; | |
| drmWaitVBlank(fd, &vbl); | |
| info->vbl_count++; | |
| if (info->vbl_count == 60) { | |
| gettimeofday(&end, NULL); | |
| t = end.tv_sec + end.tv_usec * 1e-6 - | |
| (info->start.tv_sec + info->start.tv_usec * 1e-6); | |
| fprintf(stderr, "freq: %.02fHz\n", info->vbl_count / t); | |
| info->vbl_count = 0; | |
| info->start = end; | |
| } | |
| } | |
| static void usage(char *name) | |
| { | |
| fprintf(stderr, "usage: %s [-DMs]\n", name); | |
| fprintf(stderr, "\n"); | |
| fprintf(stderr, "options:\n"); | |
| fprintf(stderr, " -D DEVICE open the given device\n"); | |
| fprintf(stderr, " -M MODULE open the given module\n"); | |
| fprintf(stderr, " -s use secondary pipe\n"); | |
| exit(0); | |
| } | |
| int main(int argc, char **argv) | |
| { | |
| const char *device = NULL, *module = NULL; | |
| int c, fd, ret; | |
| drmVBlank vbl; | |
| drmEventContext evctx; | |
| struct vbl_info handler_info; | |
| opterr = 0; | |
| while ((c = getopt(argc, argv, optstr)) != -1) { | |
| switch (c) { | |
| case 'D': | |
| device = optarg; | |
| break; | |
| case 'M': | |
| module = optarg; | |
| break; | |
| case 's': | |
| secondary = 1; | |
| break; | |
| default: | |
| usage(argv[0]); | |
| break; | |
| } | |
| } | |
| fd = util_open(device, module); | |
| if (fd < 0) | |
| return 1; | |
| /* Get current count first */ | |
| vbl.request.type = DRM_VBLANK_RELATIVE; | |
| if (secondary) | |
| vbl.request.type |= DRM_VBLANK_SECONDARY; | |
| vbl.request.sequence = 0; | |
| ret = drmWaitVBlank(fd, &vbl); | |
| if (ret != 0) { | |
| printf("drmWaitVBlank (relative) failed ret: %i\n", ret); | |
| return -1; | |
| } | |
| printf("starting count: %d\n", vbl.request.sequence); | |
| handler_info.vbl_count = 0; | |
| gettimeofday(&handler_info.start, NULL); | |
| /* Queue an event for frame + 1 */ | |
| vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; | |
| if (secondary) | |
| vbl.request.type |= DRM_VBLANK_SECONDARY; | |
| vbl.request.sequence = 1; | |
| vbl.request.signal = (unsigned long)&handler_info; | |
| ret = drmWaitVBlank(fd, &vbl); | |
| if (ret != 0) { | |
| printf("drmWaitVBlank (relative, event) failed ret: %i\n", ret); | |
| return -1; | |
| } | |
| /* Set up our event handler */ | |
| memset(&evctx, 0, sizeof evctx); | |
| evctx.version = DRM_EVENT_CONTEXT_VERSION; | |
| evctx.vblank_handler = vblank_handler; | |
| evctx.page_flip_handler = NULL; | |
| /* Poll for events */ | |
| while (1) { | |
| struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; | |
| fd_set fds; | |
| FD_ZERO(&fds); | |
| FD_SET(0, &fds); | |
| FD_SET(fd, &fds); | |
| ret = select(fd + 1, &fds, NULL, NULL, &timeout); | |
| if (ret <= 0) { | |
| fprintf(stderr, "select timed out or error (ret %d)\n", | |
| ret); | |
| continue; | |
| } else if (FD_ISSET(0, &fds)) { | |
| break; | |
| } | |
| ret = drmHandleEvent(fd, &evctx); | |
| if (ret != 0) { | |
| printf("drmHandleEvent failed: %i\n", ret); | |
| return -1; | |
| } | |
| } | |
| return 0; | |
| } |