modetest: add cursor support
authorRob Clark <robclark@freedesktop.org>
Tue, 22 Apr 2014 14:33:12 +0000 (10:33 -0400)
committerRob Clark <robclark@freedesktop.org>
Tue, 22 Apr 2014 15:14:12 +0000 (11:14 -0400)
Signed-off-by: Rob Clark <robclark@freedesktop.org>
tests/modetest/Makefile.am
tests/modetest/cursor.c [new file with mode: 0644]
tests/modetest/cursor.h [new file with mode: 0644]
tests/modetest/modetest.c

index 6e7ff14..fd6ebb2 100644 (file)
@@ -14,7 +14,9 @@ noinst_PROGRAMS = \
 endif
 
 modetest_SOURCES = \
-       buffers.c modetest.c buffers.h
+       buffers.c buffers.h \
+       cursor.c cursor.h \
+       modetest.c
 
 modetest_LDADD = \
        $(top_builddir)/libdrm.la \
diff --git a/tests/modetest/cursor.c b/tests/modetest/cursor.c
new file mode 100644 (file)
index 0000000..7077f20
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * DRM based mode setting test program
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/time.h>
+
+#include "xf86drm.h"
+#include "xf86drmMode.h"
+
+#include "buffers.h"
+#include "cursor.h"
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+struct cursor {
+       int fd;
+       uint32_t bo_handle;
+       uint32_t crtc_id;
+       uint32_t crtc_w, crtc_h;
+       uint32_t w, h;
+
+       /* current state */
+       uint32_t enabled, x, y;
+       int32_t dx, dy;
+};
+
+#define MAX_CURSORS 8
+static struct cursor cursors[MAX_CURSORS];
+static int ncursors;
+
+/*
+ * Timer driven program loops through these steps to move/enable/disable
+ * the cursor
+ */
+
+struct cursor_step {
+       void (*run)(struct cursor *cursor, struct cursor_step *step);
+       uint32_t msec;
+       uint32_t repeat;
+       int arg;
+};
+
+static uint32_t indx, count;
+
+static void set_cursor(struct cursor *cursor, struct cursor_step *step)
+{
+       int enabled = (step->arg ^ count) & 0x1;
+       uint32_t handle = 0;
+
+       if (enabled)
+               handle = cursor->bo_handle;
+
+       cursor->enabled = enabled;
+
+       drmModeSetCursor(cursor->fd, cursor->crtc_id, handle, cursor->w, cursor->h);
+}
+
+static void move_cursor(struct cursor *cursor, struct cursor_step *step)
+{
+       int x = cursor->x;
+       int y = cursor->y;
+
+       if (!cursor->enabled)
+               drmModeSetCursor(cursor->fd, cursor->crtc_id,
+                               cursor->bo_handle, cursor->w, cursor->h);
+
+       /* calculate new cursor position: */
+       x += cursor->dx * step->arg;
+       y += cursor->dy * step->arg;
+
+       if (x < 0) {
+               x = 0;
+               cursor->dx = 1;
+       } else if (x > (int)cursor->crtc_w) {
+               x = cursor->crtc_w - 1;
+               cursor->dx = -1;
+       }
+
+       if (y < 0) {
+               y = 0;
+               cursor->dy = 1;
+       } else if (y > (int)cursor->crtc_h) {
+               y = cursor->crtc_h - 1;
+               cursor->dy = -1;
+       }
+
+       cursor->x = x;
+       cursor->y = y;
+
+       drmModeMoveCursor(cursor->fd, cursor->crtc_id, x, y);
+}
+
+static struct cursor_step steps[] = {
+               {  set_cursor, 10,   0,  1 },  /* enable */
+               { move_cursor,  1, 100,  1 },
+               { move_cursor,  1,  10, 10 },
+               {  set_cursor,  1, 100,  0 },  /* disable/enable loop */
+               { move_cursor,  1,  10, 10 },
+               { move_cursor,  9, 100,  1 },
+               { move_cursor, 11, 100,  5 },
+               {  set_cursor, 17,  10,  0 },  /* disable/enable loop */
+               { move_cursor,  9, 100,  1 },
+               {  set_cursor, 13,  10,  0 },  /* disable/enable loop */
+               { move_cursor,  9, 100,  1 },
+               {  set_cursor, 13,  10,  0 },  /* disable/enable loop */
+               {  set_cursor, 10,   0,  0 },  /* disable */
+};
+
+/*
+ * Cursor API:
+ */
+
+static void run_step(int sig)
+{
+       struct cursor_step *step = &steps[indx % ARRAY_SIZE(steps)];
+       struct itimerval itimer = {
+                       .it_value.tv_usec = 1000 * step->msec,
+       };
+       int i;
+
+       for (i = 0; i < ncursors; i++) {
+               struct cursor *cursor = &cursors[i];
+               step->run(cursor, step);
+       }
+
+       /* iterate to next count/step: */
+       if (count < step->repeat) {
+               count++;
+       } else {
+               count = 0;
+               indx++;
+       }
+
+       /* and lastly, setup timer for next step */
+       setitimer(ITIMER_REAL, &itimer, NULL);
+}
+
+int cursor_init(int fd, uint32_t bo_handle, uint32_t crtc_id,
+               uint32_t crtc_w, uint32_t crtc_h, uint32_t w, uint32_t h)
+{
+       struct cursor *cursor = &cursors[ncursors];
+
+       assert(ncursors < MAX_CURSORS);
+
+       cursor->fd = fd;
+       cursor->bo_handle = bo_handle;
+       cursor->crtc_id = crtc_id;
+       cursor->crtc_w = crtc_w;
+       cursor->crtc_h = crtc_h;
+       cursor->w = w;
+       cursor->h = h;
+
+       cursor->enabled = 0;
+       cursor->x = w/2;
+       cursor->y = h/2;
+       cursor->dx = 1;
+       cursor->dy = 1;
+
+       ncursors++;
+
+       return 0;
+}
+
+int cursor_start(void)
+{
+       /* setup signal handler to update cursor: */
+       signal(SIGALRM, run_step);
+       printf("starting cursor\n");
+       run_step(SIGALRM);
+       return 0;
+}
+
+int cursor_stop(void)
+{
+       signal(SIGALRM, NULL);
+       printf("cursor stopped\n");
+       return 0;
+}
diff --git a/tests/modetest/cursor.h b/tests/modetest/cursor.h
new file mode 100644 (file)
index 0000000..d849f6c
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * DRM based mode setting test program
+ * Copyright (C) 2014 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ */
+
+#ifndef __CURSOR_H__
+#define __CURSOR_H__
+
+int cursor_init(int fd, uint32_t bo_handle, uint32_t crtc_id,
+               uint32_t crtc_w, uint32_t crtc_h, uint32_t w, uint32_t h);
+int cursor_start(void);
+int cursor_stop(void);
+
+#endif
index bc9c998..7d436b5 100644 (file)
@@ -58,6 +58,7 @@
 #include "libkms.h"
 
 #include "buffers.h"
+#include "cursor.h"
 
 struct crtc {
        drmModeCrtc *crtc;
@@ -1104,6 +1105,46 @@ static void set_planes(struct device *dev, struct plane_arg *p, unsigned int cou
                        return;
 }
 
+static void set_cursors(struct device *dev, struct pipe_arg *pipes, unsigned int count)
+{
+       uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */
+       struct kms_bo *bo;
+       unsigned int i;
+       int ret;
+
+       /* maybe make cursor width/height configurable some day */
+       uint32_t cw = 64;
+       uint32_t ch = 64;
+
+       /* create cursor bo.. just using PATTERN_PLAIN as it has
+        * translucent alpha
+        */
+       bo = create_test_buffer(dev->kms, DRM_FORMAT_ARGB8888,
+                       cw, ch, handles, pitches, offsets, PATTERN_PLAIN);
+       if (bo == NULL)
+               return;
+
+       for (i = 0; i < count; i++) {
+               struct pipe_arg *pipe = &pipes[i];
+               ret = cursor_init(dev->fd, handles[0],
+                               pipe->crtc->crtc->crtc_id,
+                               pipe->mode->hdisplay, pipe->mode->vdisplay,
+                               cw, ch);
+               if (ret) {
+                       fprintf(stderr, "failed to init cursor for CRTC[%u]\n",
+                                       pipe->crtc_id);
+                       return;
+               }
+       }
+
+       cursor_start();
+}
+
+static void clear_cursors(struct device *dev)
+{
+       cursor_stop();
+}
+
 static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned int count)
 {
        uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */
@@ -1332,7 +1373,7 @@ static int parse_property(struct property_arg *p, const char *arg)
 
 static void usage(char *name)
 {
-       fprintf(stderr, "usage: %s [-cDdefMPpsvw]\n", name);
+       fprintf(stderr, "usage: %s [-cDdefMPpsCvw]\n", name);
 
        fprintf(stderr, "\n Query options:\n\n");
        fprintf(stderr, "\t-c\tlist connectors\n");
@@ -1343,6 +1384,7 @@ static void usage(char *name)
        fprintf(stderr, "\n Test options:\n\n");
        fprintf(stderr, "\t-P <crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n");
        fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[-<vrefresh>][@<format>]\tset a mode\n");
+       fprintf(stderr, "\t-C\ttest hw cursor\n");
        fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
        fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n");
 
@@ -1376,7 +1418,13 @@ static int page_flipping_supported(void)
 #endif
 }
 
-static char optstr[] = "cdD:efM:P:ps:vw:";
+static int cursor_supported(void)
+{
+       /*FIXME: generic ioctl needed? */
+       return 1;
+}
+
+static char optstr[] = "cdD:efM:P:ps:Cvw:";
 
 int main(int argc, char **argv)
 {
@@ -1386,6 +1434,7 @@ int main(int argc, char **argv)
        int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0;
        int drop_master = 0;
        int test_vsync = 0;
+       int test_cursor = 0;
        const char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "omapdrm", "exynos", "tilcdc", "msm" };
        char *device = NULL;
        char *module = NULL;
@@ -1456,6 +1505,9 @@ int main(int argc, char **argv)
 
                        count++;                                      
                        break;
+               case 'C':
+                       test_cursor = 1;
+                       break;
                case 'v':
                        test_vsync = 1;
                        break;
@@ -1515,6 +1567,11 @@ int main(int argc, char **argv)
                return -1;
        }
 
+       if (test_cursor && !cursor_supported()) {
+               fprintf(stderr, "hw cursor not supported by drm.\n");
+               return -1;
+       }
+
        dev.resources = get_resources(&dev);
        if (!dev.resources) {
                drmClose(dev.fd);
@@ -1546,16 +1603,22 @@ int main(int argc, char **argv)
                if (plane_count)
                        set_planes(&dev, plane_args, plane_count);
 
+               if (test_cursor)
+                       set_cursors(&dev, pipe_args, count);
+
                if (test_vsync)
                        test_page_flip(&dev, pipe_args, count);
 
                if (drop_master)
                        drmDropMaster(dev.fd);
 
+               getchar();
+
+               if (test_cursor)
+                       clear_cursors(&dev);
+
                kms_bo_destroy(&dev.mode.bo);
                kms_destroy(&dev.kms);
-
-               getchar();
        }
 
        free_resources(dev.resources);