Back to index

libdrm  2.4.37
vbltest.c
Go to the documentation of this file.
00001 /*
00002  * DRM based mode setting test program
00003  * Copyright 2008 Tungsten Graphics
00004  *   Jakob Bornecrantz <jakob@tungstengraphics.com>
00005  * Copyright 2008 Intel Corporation
00006  *   Jesse Barnes <jesse.barnes@intel.com>
00007  *
00008  * Permission is hereby granted, free of charge, to any person obtaining a
00009  * copy of this software and associated documentation files (the "Software"),
00010  * to deal in the Software without restriction, including without limitation
00011  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00012  * and/or sell copies of the Software, and to permit persons to whom the
00013  * Software is furnished to do so, subject to the following conditions:
00014  *
00015  * The above copyright notice and this permission notice shall be included in
00016  * all copies or substantial portions of the Software.
00017  *
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00019  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00020  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00021  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00022  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00023  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
00024  * IN THE SOFTWARE.
00025  */
00026 
00027 /*
00028  * This fairly simple test program dumps output in a similar format to the
00029  * "xrandr" tool everyone knows & loves.  It's necessarily slightly different
00030  * since the kernel separates outputs into encoder and connector structures,
00031  * each with their own unique ID.  The program also allows test testing of the
00032  * memory management and mode setting APIs by allowing the user to specify a
00033  * connector and mode to use for mode setting.  If all works as expected, a
00034  * blue background should be painted on the monitor attached to the specified
00035  * connector after the selected mode is set.
00036  *
00037  * TODO: use cairo to write the mode info on the selected output once
00038  *       the mode has been programmed, along with possible test patterns.
00039  */
00040 #include "config.h"
00041 
00042 #include <assert.h>
00043 #include <stdio.h>
00044 #include <stdlib.h>
00045 #include <stdint.h>
00046 #include <unistd.h>
00047 #include <string.h>
00048 #include <errno.h>
00049 #include <sys/poll.h>
00050 #include <sys/time.h>
00051 
00052 #include "xf86drm.h"
00053 #include "xf86drmMode.h"
00054 
00055 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
00056 
00057 extern char *optarg;
00058 extern int optind, opterr, optopt;
00059 static char optstr[] = "s";
00060 
00061 int secondary = 0;
00062 
00063 struct vbl_info {
00064        unsigned int vbl_count;
00065        struct timeval start;
00066 };
00067 
00068 static void vblank_handler(int fd, unsigned int frame, unsigned int sec,
00069                         unsigned int usec, void *data)
00070 {
00071        drmVBlank vbl;
00072        struct timeval end;
00073        struct vbl_info *info = data;
00074        double t;
00075 
00076        vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
00077        if (secondary)
00078               vbl.request.type |= DRM_VBLANK_SECONDARY;
00079        vbl.request.sequence = 1;
00080        vbl.request.signal = (unsigned long)data;
00081 
00082        drmWaitVBlank(fd, &vbl);
00083 
00084        info->vbl_count++;
00085 
00086        if (info->vbl_count == 60) {
00087               gettimeofday(&end, NULL);
00088               t = end.tv_sec + end.tv_usec * 1e-6 -
00089                      (info->start.tv_sec + info->start.tv_usec * 1e-6);
00090               fprintf(stderr, "freq: %.02fHz\n", info->vbl_count / t);
00091               info->vbl_count = 0;
00092               info->start = end;
00093        }
00094 }
00095 
00096 static void usage(char *name)
00097 {
00098        fprintf(stderr, "usage: %s [-s]\n", name);
00099        fprintf(stderr, "\t-s\tuse secondary pipe\n");
00100        exit(0);
00101 }
00102 
00103 int main(int argc, char **argv)
00104 {
00105        int i, c, fd, ret;
00106        char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "exynos" };
00107        drmVBlank vbl;
00108        drmEventContext evctx;
00109        struct vbl_info handler_info;
00110 
00111        opterr = 0;
00112        while ((c = getopt(argc, argv, optstr)) != -1) {
00113               switch (c) {
00114               case 's':
00115                      secondary = 1;
00116                      break;
00117               default:
00118                      usage(argv[0]);
00119                      break;
00120               }
00121        }
00122 
00123        for (i = 0; i < ARRAY_SIZE(modules); i++) {
00124               printf("trying to load module %s...", modules[i]);
00125               fd = drmOpen(modules[i], NULL);
00126               if (fd < 0) {
00127                      printf("failed.\n");
00128               } else {
00129                      printf("success.\n");
00130                      break;
00131               }
00132        }
00133 
00134        if (i == ARRAY_SIZE(modules)) {
00135               fprintf(stderr, "failed to load any modules, aborting.\n");
00136               return -1;
00137        }
00138 
00139        /* Get current count first */
00140        vbl.request.type = DRM_VBLANK_RELATIVE;
00141        if (secondary)
00142               vbl.request.type |= DRM_VBLANK_SECONDARY;
00143        vbl.request.sequence = 0;
00144        ret = drmWaitVBlank(fd, &vbl);
00145        if (ret != 0) {
00146               printf("drmWaitVBlank (relative) failed ret: %i\n", ret);
00147               return -1;
00148        }
00149 
00150        printf("starting count: %d\n", vbl.request.sequence);
00151 
00152        handler_info.vbl_count = 0;
00153        gettimeofday(&handler_info.start, NULL);
00154 
00155        /* Queue an event for frame + 1 */
00156        vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
00157        if (secondary)
00158               vbl.request.type |= DRM_VBLANK_SECONDARY;
00159        vbl.request.sequence = 1;
00160        vbl.request.signal = (unsigned long)&handler_info;
00161        ret = drmWaitVBlank(fd, &vbl);
00162        if (ret != 0) {
00163               printf("drmWaitVBlank (relative, event) failed ret: %i\n", ret);
00164               return -1;
00165        }
00166 
00167        /* Set up our event handler */
00168        memset(&evctx, 0, sizeof evctx);
00169        evctx.version = DRM_EVENT_CONTEXT_VERSION;
00170        evctx.vblank_handler = vblank_handler;
00171        evctx.page_flip_handler = NULL;
00172 
00173        /* Poll for events */
00174        while (1) {
00175               struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
00176               fd_set fds;
00177               int ret;
00178 
00179               FD_ZERO(&fds);
00180               FD_SET(0, &fds);
00181               FD_SET(fd, &fds);
00182               ret = select(fd + 1, &fds, NULL, NULL, &timeout);
00183 
00184               if (ret <= 0) {
00185                      fprintf(stderr, "select timed out or error (ret %d)\n",
00186                             ret);
00187                      continue;
00188               } else if (FD_ISSET(0, &fds)) {
00189                      break;
00190               }
00191 
00192               ret = drmHandleEvent(fd, &evctx);
00193               if (ret != 0) {
00194                      printf("drmHandleEvent failed: %i\n", ret);
00195                      return -1;
00196               }
00197        }
00198 
00199        return 0;
00200 }