diff --git a/tests/modetest/Makefile.am b/tests/modetest/Makefile.am index 6e7ff14f..fd6ebb22 100644 --- a/tests/modetest/Makefile.am +++ b/tests/modetest/Makefile.am @@ -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 index 00000000..7077f203 --- /dev/null +++ b/tests/modetest/cursor.c @@ -0,0 +1,207 @@ +/* + * DRM based mode setting test program + * Copyright (C) 2013 Red Hat + * Author: Rob Clark + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 index 00000000..d849f6c4 --- /dev/null +++ b/tests/modetest/cursor.h @@ -0,0 +1,33 @@ +/* + * DRM based mode setting test program + * Copyright (C) 2014 Red Hat + * Author: Rob Clark + * + * 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 diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index bc9c9988..7d436b56 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -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 :x[++][*][@]\tset a plane\n"); fprintf(stderr, "\t-s [,][@]:[-][@]\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 ::\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);