cursor.c revision 857b0bc6
1857b0bc6Smrg/*
2857b0bc6Smrg * DRM based mode setting test program
3857b0bc6Smrg * Copyright (C) 2013 Red Hat
4857b0bc6Smrg * Author: Rob Clark <robdclark@gmail.com>
5857b0bc6Smrg *
6857b0bc6Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7857b0bc6Smrg * copy of this software and associated documentation files (the "Software"),
8857b0bc6Smrg * to deal in the Software without restriction, including without limitation
9857b0bc6Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10857b0bc6Smrg * and/or sell copies of the Software, and to permit persons to whom the
11857b0bc6Smrg * Software is furnished to do so, subject to the following conditions:
12857b0bc6Smrg *
13857b0bc6Smrg * The above copyright notice and this permission notice shall be included in
14857b0bc6Smrg * all copies or substantial portions of the Software.
15857b0bc6Smrg *
16857b0bc6Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17857b0bc6Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18857b0bc6Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19857b0bc6Smrg * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20857b0bc6Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21857b0bc6Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22857b0bc6Smrg * IN THE SOFTWARE.
23857b0bc6Smrg */
24857b0bc6Smrg
25857b0bc6Smrg#include "config.h"
26857b0bc6Smrg
27857b0bc6Smrg#include <assert.h>
28857b0bc6Smrg#include <errno.h>
29857b0bc6Smrg#include <stdio.h>
30857b0bc6Smrg#include <stdlib.h>
31857b0bc6Smrg#include <stdint.h>
32857b0bc6Smrg#include <string.h>
33857b0bc6Smrg#include <signal.h>
34857b0bc6Smrg#include <sys/time.h>
35857b0bc6Smrg
36857b0bc6Smrg#include "xf86drm.h"
37857b0bc6Smrg#include "xf86drmMode.h"
38857b0bc6Smrg
39857b0bc6Smrg#include "buffers.h"
40857b0bc6Smrg#include "cursor.h"
41857b0bc6Smrg
42857b0bc6Smrg#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
43857b0bc6Smrg
44857b0bc6Smrgstruct cursor {
45857b0bc6Smrg	int fd;
46857b0bc6Smrg	uint32_t bo_handle;
47857b0bc6Smrg	uint32_t crtc_id;
48857b0bc6Smrg	uint32_t crtc_w, crtc_h;
49857b0bc6Smrg	uint32_t w, h;
50857b0bc6Smrg
51857b0bc6Smrg	/* current state */
52857b0bc6Smrg	uint32_t enabled, x, y;
53857b0bc6Smrg	int32_t dx, dy;
54857b0bc6Smrg};
55857b0bc6Smrg
56857b0bc6Smrg#define MAX_CURSORS 8
57857b0bc6Smrgstatic struct cursor cursors[MAX_CURSORS];
58857b0bc6Smrgstatic int ncursors;
59857b0bc6Smrg
60857b0bc6Smrg/*
61857b0bc6Smrg * Timer driven program loops through these steps to move/enable/disable
62857b0bc6Smrg * the cursor
63857b0bc6Smrg */
64857b0bc6Smrg
65857b0bc6Smrgstruct cursor_step {
66857b0bc6Smrg	void (*run)(struct cursor *cursor, struct cursor_step *step);
67857b0bc6Smrg	uint32_t msec;
68857b0bc6Smrg	uint32_t repeat;
69857b0bc6Smrg	int arg;
70857b0bc6Smrg};
71857b0bc6Smrg
72857b0bc6Smrgstatic uint32_t indx, count;
73857b0bc6Smrg
74857b0bc6Smrgstatic void set_cursor(struct cursor *cursor, struct cursor_step *step)
75857b0bc6Smrg{
76857b0bc6Smrg	int enabled = (step->arg ^ count) & 0x1;
77857b0bc6Smrg	uint32_t handle = 0;
78857b0bc6Smrg
79857b0bc6Smrg	if (enabled)
80857b0bc6Smrg		handle = cursor->bo_handle;
81857b0bc6Smrg
82857b0bc6Smrg	cursor->enabled = enabled;
83857b0bc6Smrg
84857b0bc6Smrg	drmModeSetCursor(cursor->fd, cursor->crtc_id, handle, cursor->w, cursor->h);
85857b0bc6Smrg}
86857b0bc6Smrg
87857b0bc6Smrgstatic void move_cursor(struct cursor *cursor, struct cursor_step *step)
88857b0bc6Smrg{
89857b0bc6Smrg	int x = cursor->x;
90857b0bc6Smrg	int y = cursor->y;
91857b0bc6Smrg
92857b0bc6Smrg	if (!cursor->enabled)
93857b0bc6Smrg		drmModeSetCursor(cursor->fd, cursor->crtc_id,
94857b0bc6Smrg				cursor->bo_handle, cursor->w, cursor->h);
95857b0bc6Smrg
96857b0bc6Smrg	/* calculate new cursor position: */
97857b0bc6Smrg	x += cursor->dx * step->arg;
98857b0bc6Smrg	y += cursor->dy * step->arg;
99857b0bc6Smrg
100857b0bc6Smrg	if (x < 0) {
101857b0bc6Smrg		x = 0;
102857b0bc6Smrg		cursor->dx = 1;
103857b0bc6Smrg	} else if (x > (int)cursor->crtc_w) {
104857b0bc6Smrg		x = cursor->crtc_w - 1;
105857b0bc6Smrg		cursor->dx = -1;
106857b0bc6Smrg	}
107857b0bc6Smrg
108857b0bc6Smrg	if (y < 0) {
109857b0bc6Smrg		y = 0;
110857b0bc6Smrg		cursor->dy = 1;
111857b0bc6Smrg	} else if (y > (int)cursor->crtc_h) {
112857b0bc6Smrg		y = cursor->crtc_h - 1;
113857b0bc6Smrg		cursor->dy = -1;
114857b0bc6Smrg	}
115857b0bc6Smrg
116857b0bc6Smrg	cursor->x = x;
117857b0bc6Smrg	cursor->y = y;
118857b0bc6Smrg
119857b0bc6Smrg	drmModeMoveCursor(cursor->fd, cursor->crtc_id, x, y);
120857b0bc6Smrg}
121857b0bc6Smrg
122857b0bc6Smrgstatic struct cursor_step steps[] = {
123857b0bc6Smrg		{  set_cursor, 10,   0,  1 },  /* enable */
124857b0bc6Smrg		{ move_cursor,  1, 100,  1 },
125857b0bc6Smrg		{ move_cursor,  1,  10, 10 },
126857b0bc6Smrg		{  set_cursor,  1, 100,  0 },  /* disable/enable loop */
127857b0bc6Smrg		{ move_cursor,  1,  10, 10 },
128857b0bc6Smrg		{ move_cursor,  9, 100,  1 },
129857b0bc6Smrg		{ move_cursor, 11, 100,  5 },
130857b0bc6Smrg		{  set_cursor, 17,  10,  0 },  /* disable/enable loop */
131857b0bc6Smrg		{ move_cursor,  9, 100,  1 },
132857b0bc6Smrg		{  set_cursor, 13,  10,  0 },  /* disable/enable loop */
133857b0bc6Smrg		{ move_cursor,  9, 100,  1 },
134857b0bc6Smrg		{  set_cursor, 13,  10,  0 },  /* disable/enable loop */
135857b0bc6Smrg		{  set_cursor, 10,   0,  0 },  /* disable */
136857b0bc6Smrg};
137857b0bc6Smrg
138857b0bc6Smrg/*
139857b0bc6Smrg * Cursor API:
140857b0bc6Smrg */
141857b0bc6Smrg
142857b0bc6Smrgstatic void run_step(int sig)
143857b0bc6Smrg{
144857b0bc6Smrg	struct cursor_step *step = &steps[indx % ARRAY_SIZE(steps)];
145857b0bc6Smrg	struct itimerval itimer = {
146857b0bc6Smrg			.it_value.tv_usec = 1000 * step->msec,
147857b0bc6Smrg	};
148857b0bc6Smrg	int i;
149857b0bc6Smrg
150857b0bc6Smrg	for (i = 0; i < ncursors; i++) {
151857b0bc6Smrg		struct cursor *cursor = &cursors[i];
152857b0bc6Smrg		step->run(cursor, step);
153857b0bc6Smrg	}
154857b0bc6Smrg
155857b0bc6Smrg	/* iterate to next count/step: */
156857b0bc6Smrg	if (count < step->repeat) {
157857b0bc6Smrg		count++;
158857b0bc6Smrg	} else {
159857b0bc6Smrg		count = 0;
160857b0bc6Smrg		indx++;
161857b0bc6Smrg	}
162857b0bc6Smrg
163857b0bc6Smrg	/* and lastly, setup timer for next step */
164857b0bc6Smrg	setitimer(ITIMER_REAL, &itimer, NULL);
165857b0bc6Smrg}
166857b0bc6Smrg
167857b0bc6Smrgint cursor_init(int fd, uint32_t bo_handle, uint32_t crtc_id,
168857b0bc6Smrg		uint32_t crtc_w, uint32_t crtc_h, uint32_t w, uint32_t h)
169857b0bc6Smrg{
170857b0bc6Smrg	struct cursor *cursor = &cursors[ncursors];
171857b0bc6Smrg
172857b0bc6Smrg	assert(ncursors < MAX_CURSORS);
173857b0bc6Smrg
174857b0bc6Smrg	cursor->fd = fd;
175857b0bc6Smrg	cursor->bo_handle = bo_handle;
176857b0bc6Smrg	cursor->crtc_id = crtc_id;
177857b0bc6Smrg	cursor->crtc_w = crtc_w;
178857b0bc6Smrg	cursor->crtc_h = crtc_h;
179857b0bc6Smrg	cursor->w = w;
180857b0bc6Smrg	cursor->h = h;
181857b0bc6Smrg
182857b0bc6Smrg	cursor->enabled = 0;
183857b0bc6Smrg	cursor->x = w/2;
184857b0bc6Smrg	cursor->y = h/2;
185857b0bc6Smrg	cursor->dx = 1;
186857b0bc6Smrg	cursor->dy = 1;
187857b0bc6Smrg
188857b0bc6Smrg	ncursors++;
189857b0bc6Smrg
190857b0bc6Smrg	return 0;
191857b0bc6Smrg}
192857b0bc6Smrg
193857b0bc6Smrgint cursor_start(void)
194857b0bc6Smrg{
195857b0bc6Smrg	/* setup signal handler to update cursor: */
196857b0bc6Smrg	signal(SIGALRM, run_step);
197857b0bc6Smrg	printf("starting cursor\n");
198857b0bc6Smrg	run_step(SIGALRM);
199857b0bc6Smrg	return 0;
200857b0bc6Smrg}
201857b0bc6Smrg
202857b0bc6Smrgint cursor_stop(void)
203857b0bc6Smrg{
204857b0bc6Smrg	signal(SIGALRM, NULL);
205857b0bc6Smrg	printf("cursor stopped\n");
206857b0bc6Smrg	return 0;
207857b0bc6Smrg}
208