10e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark/*
20e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * DRM based mode setting test program
30e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * Copyright (C) 2013 Red Hat
40e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * Author: Rob Clark <robdclark@gmail.com>
50e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark *
60e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * Permission is hereby granted, free of charge, to any person obtaining a
70e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * copy of this software and associated documentation files (the "Software"),
80e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * to deal in the Software without restriction, including without limitation
90e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * the rights to use, copy, modify, merge, publish, distribute, sublicense,
100e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * and/or sell copies of the Software, and to permit persons to whom the
110e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * Software is furnished to do so, subject to the following conditions:
120e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark *
130e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * The above copyright notice and this permission notice shall be included in
140e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * all copies or substantial portions of the Software.
150e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark *
160e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
170e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
180e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
190e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
200e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
210e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
220e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * IN THE SOFTWARE.
230e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark */
240e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
258e93afc9765f1de613c65a76e9a86e17db96e653Emil Velikov#ifdef HAVE_CONFIG_H
260e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark#include "config.h"
278e93afc9765f1de613c65a76e9a86e17db96e653Emil Velikov#endif
280e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
290e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark#include <assert.h>
300e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark#include <errno.h>
310e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark#include <stdio.h>
320e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark#include <stdlib.h>
330e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark#include <stdint.h>
340e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark#include <string.h>
350e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark#include <signal.h>
360e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark#include <sys/time.h>
3729bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre#include <pthread.h>
3829bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre#include <unistd.h>
390e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
400e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark#include "xf86drm.h"
410e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark#include "xf86drmMode.h"
420e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
431ec3c44bdd38051d870f64d0b2cc7dbd59760386Thierry Reding#include "util/common.h"
441ec3c44bdd38051d870f64d0b2cc7dbd59760386Thierry Reding
450e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark#include "buffers.h"
460e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark#include "cursor.h"
470e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
480e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clarkstruct cursor {
490e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	int fd;
500e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	uint32_t bo_handle;
510e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	uint32_t crtc_id;
520e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	uint32_t crtc_w, crtc_h;
530e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	uint32_t w, h;
540e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
550e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	/* current state */
560e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	uint32_t enabled, x, y;
570e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	int32_t dx, dy;
580e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark};
590e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
600e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark#define MAX_CURSORS 8
610e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clarkstatic struct cursor cursors[MAX_CURSORS];
620e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clarkstatic int ncursors;
630e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
6429bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierrestatic pthread_t cursor_thread;
6529bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierrestatic int cursor_running;
6629bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre
670e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark/*
680e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * Timer driven program loops through these steps to move/enable/disable
690e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark * the cursor
700e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark */
710e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
720e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clarkstruct cursor_step {
7304e243262d1d71cc8e0ac42ea96fff72af9f711dEmil Velikov	void (*run)(struct cursor *cursor, const struct cursor_step *step);
740e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	uint32_t msec;
750e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	uint32_t repeat;
760e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	int arg;
770e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark};
780e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
790e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clarkstatic uint32_t indx, count;
800e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
8104e243262d1d71cc8e0ac42ea96fff72af9f711dEmil Velikovstatic void set_cursor(struct cursor *cursor, const struct cursor_step *step)
820e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark{
830e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	int enabled = (step->arg ^ count) & 0x1;
840e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	uint32_t handle = 0;
850e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
860e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	if (enabled)
870e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		handle = cursor->bo_handle;
880e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
890e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	cursor->enabled = enabled;
900e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
910e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	drmModeSetCursor(cursor->fd, cursor->crtc_id, handle, cursor->w, cursor->h);
920e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark}
930e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
9404e243262d1d71cc8e0ac42ea96fff72af9f711dEmil Velikovstatic void move_cursor(struct cursor *cursor, const struct cursor_step *step)
950e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark{
960e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	int x = cursor->x;
970e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	int y = cursor->y;
980e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
990e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	if (!cursor->enabled)
1000e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		drmModeSetCursor(cursor->fd, cursor->crtc_id,
1010e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark				cursor->bo_handle, cursor->w, cursor->h);
1020e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
1030e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	/* calculate new cursor position: */
1040e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	x += cursor->dx * step->arg;
1050e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	y += cursor->dy * step->arg;
1060e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
1070e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	if (x < 0) {
1080e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		x = 0;
1090e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		cursor->dx = 1;
1100e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	} else if (x > (int)cursor->crtc_w) {
1110e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		x = cursor->crtc_w - 1;
1120e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		cursor->dx = -1;
1130e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	}
1140e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
1150e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	if (y < 0) {
1160e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		y = 0;
1170e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		cursor->dy = 1;
1180e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	} else if (y > (int)cursor->crtc_h) {
1190e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		y = cursor->crtc_h - 1;
1200e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		cursor->dy = -1;
1210e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	}
1220e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
1230e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	cursor->x = x;
1240e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	cursor->y = y;
1250e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
1260e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	drmModeMoveCursor(cursor->fd, cursor->crtc_id, x, y);
1270e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark}
1280e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
12904e243262d1d71cc8e0ac42ea96fff72af9f711dEmil Velikovstatic const struct cursor_step steps[] = {
1300e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		{  set_cursor, 10,   0,  1 },  /* enable */
1310e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		{ move_cursor,  1, 100,  1 },
1320e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		{ move_cursor,  1,  10, 10 },
1330e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		{  set_cursor,  1, 100,  0 },  /* disable/enable loop */
1340e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		{ move_cursor,  1,  10, 10 },
1350e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		{ move_cursor,  9, 100,  1 },
1360e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		{ move_cursor, 11, 100,  5 },
1370e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		{  set_cursor, 17,  10,  0 },  /* disable/enable loop */
1380e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		{ move_cursor,  9, 100,  1 },
1390e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		{  set_cursor, 13,  10,  0 },  /* disable/enable loop */
1400e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		{ move_cursor,  9, 100,  1 },
1410e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		{  set_cursor, 13,  10,  0 },  /* disable/enable loop */
1420e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		{  set_cursor, 10,   0,  0 },  /* disable */
1430e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark};
1440e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
14529bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierrestatic void *cursor_thread_func(void *data)
1460e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark{
14729bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre	while (cursor_running) {
14804e243262d1d71cc8e0ac42ea96fff72af9f711dEmil Velikov		const struct cursor_step *step = &steps[indx % ARRAY_SIZE(steps)];
14929bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre		int i;
15029bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre
15129bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre		for (i = 0; i < ncursors; i++) {
15229bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre			struct cursor *cursor = &cursors[i];
15329bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre			step->run(cursor, step);
15429bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre		}
15529bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre
15629bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre		/* iterate to next count/step: */
15729bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre		if (count < step->repeat) {
15829bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre			count++;
15929bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre		} else {
16029bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre			count = 0;
16129bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre			indx++;
16229bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre		}
16329bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre
16429bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre		usleep(1000 * step->msec);
1650e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	}
1660e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
16729bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre	return NULL;
1680e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark}
1690e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
1700e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clarkint cursor_init(int fd, uint32_t bo_handle, uint32_t crtc_id,
1710e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark		uint32_t crtc_w, uint32_t crtc_h, uint32_t w, uint32_t h)
1720e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark{
1730e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	struct cursor *cursor = &cursors[ncursors];
1740e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
1750e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	assert(ncursors < MAX_CURSORS);
1760e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
1770e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	cursor->fd = fd;
1780e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	cursor->bo_handle = bo_handle;
1790e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	cursor->crtc_id = crtc_id;
1800e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	cursor->crtc_w = crtc_w;
1810e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	cursor->crtc_h = crtc_h;
1820e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	cursor->w = w;
1830e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	cursor->h = h;
1840e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
1850e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	cursor->enabled = 0;
1860e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	cursor->x = w/2;
1870e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	cursor->y = h/2;
1880e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	cursor->dx = 1;
1890e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	cursor->dy = 1;
1900e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
1910e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	ncursors++;
1920e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
1930e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	return 0;
1940e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark}
1950e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
1960e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clarkint cursor_start(void)
1970e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark{
19829bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre	cursor_running = 1;
19929bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre	pthread_create(&cursor_thread, NULL, cursor_thread_func, NULL);
2000e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	printf("starting cursor\n");
2010e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	return 0;
2020e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark}
2030e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark
2040e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clarkint cursor_stop(void)
2050e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark{
20629bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre	cursor_running = 0;
20729bb4c6911b21c026c3863799dcbeaa29981bf7eJasper St. Pierre	pthread_join(cursor_thread, NULL);
2080e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	printf("cursor stopped\n");
2090e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark	return 0;
2100e512794bf6281edfa4543ae7cc408d52ec6e2f3Rob Clark}
211