1 /*
2  * Copyright © 2014 NVIDIA Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include <fcntl.h>
29 #include <getopt.h>
30 #include <stdbool.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <unistd.h>
35 
36 #include <drm_fourcc.h>
37 #include "xf86drm.h"
38 
39 #include "util/common.h"
40 #include "libkms-test.h"
41 
42 static const uint32_t formats[] = {
43 	DRM_FORMAT_XRGB8888,
44 	DRM_FORMAT_XBGR8888,
45 	DRM_FORMAT_RGBA8888,
46 };
47 
choose_format(struct kms_plane * plane)48 static uint32_t choose_format(struct kms_plane *plane)
49 {
50 	unsigned int i;
51 
52 	for (i = 0; i < ARRAY_SIZE(formats); i++)
53 		if (kms_plane_supports_format(plane, formats[i]))
54 			return formats[i];
55 
56 	return 0;
57 }
58 
prepare_framebuffer(struct kms_framebuffer * fb,bool invert)59 static void prepare_framebuffer(struct kms_framebuffer *fb, bool invert)
60 {
61 	const unsigned int block_size = 16;
62 	uint32_t colors[2];
63 	unsigned int i, j;
64 	uint32_t *buf;
65 	void *ptr;
66 	int err;
67 
68 	switch (fb->format) {
69 	case DRM_FORMAT_XRGB8888:
70 		printf("using XRGB8888 format\n");
71 		           /* XXRRGGBB */
72 		colors[0] = 0xffff0000;
73 		colors[1] = 0xff0000ff;
74 		break;
75 
76 	case DRM_FORMAT_XBGR8888:
77 		printf("using XBGR8888 format\n");
78 		           /* XXBBGGRR */
79 		colors[0] = 0xff0000ff;
80 		colors[1] = 0xffff0000;
81 		break;
82 
83 	case DRM_FORMAT_RGBA8888:
84 		printf("using RGBA8888 format\n");
85 		           /* RRGGBBAA */
86 		colors[0] = 0xff0000ff;
87 		colors[1] = 0x0000ffff;
88 		break;
89 
90 	default:
91 		colors[0] = 0xffffffff;
92 		colors[1] = 0xffffffff;
93 		break;
94 	}
95 
96 	err = kms_framebuffer_map(fb, &ptr);
97 	if (err < 0) {
98 		fprintf(stderr, "kms_framebuffer_map() failed: %s\n",
99 			strerror(-err));
100 		return;
101 	}
102 
103 	buf = ptr;
104 
105 	for (j = 0; j < fb->height; j++) {
106 		for (i = 0; i < fb->width; i++) {
107 			unsigned int color = (j / block_size) ^
108 					     (i / block_size);
109 
110 			if (invert)
111 				color ^= color;
112 
113 			*buf++ = colors[color & 1];
114 		}
115 	}
116 
117 	kms_framebuffer_unmap(fb);
118 }
119 
main(int argc,char * argv[])120 int main(int argc, char *argv[])
121 {
122 	static const char opts[] = "chopv";
123 	static struct option options[] = {
124 		{ "cursor", 0, 0, 'c' },
125 		{ "help", 0, 0, 'h' },
126 		{ "overlay", 0, 0, 'o' },
127 		{ "primary", 0, 0, 'p' },
128 		{ "verbose", 0, 0, 'v' },
129 		{ 0, 0, 0, 0 },
130 	};
131 	struct kms_framebuffer *cursor = NULL;
132 	struct kms_framebuffer *root = NULL;
133 	struct kms_framebuffer *fb = NULL;
134 	struct kms_device *device;
135 	bool use_overlay = false;
136 	bool use_primary = false;
137 	struct kms_plane *plane;
138 	bool use_cursor = false;
139 	bool verbose = false;
140 	unsigned int i;
141 	int opt, idx;
142 	int fd, err;
143 
144 	while ((opt = getopt_long(argc, argv, opts, options, &idx)) != -1) {
145 		switch (opt) {
146 		case 'c':
147 			use_cursor = true;
148 			break;
149 
150 		case 'h':
151 			break;
152 
153 		case 'o':
154 			use_overlay = true;
155 			break;
156 
157 		case 'p':
158 			use_primary = true;
159 			break;
160 
161 		case 'v':
162 			verbose = true;
163 			break;
164 
165 		default:
166 			printf("unknown option \"%c\"\n", opt);
167 			return 1;
168 		}
169 	}
170 
171 	if (optind >= argc) {
172 		fprintf(stderr, "usage: %s [options] DEVICE\n", argv[0]);
173 		return 1;
174 	}
175 
176 	fd = open(argv[optind], O_RDWR);
177 	if (fd < 0) {
178 		fprintf(stderr, "open() failed: %m\n");
179 		return 1;
180 	}
181 
182 	err = drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
183 	if (err < 0) {
184 		fprintf(stderr, "drmSetClientCap() failed: %d\n", err);
185 		return 1;
186 	}
187 
188 	device = kms_device_open(fd);
189 	if (!device)
190 		return 1;
191 
192 	if (verbose) {
193 		printf("Screens: %u\n", device->num_screens);
194 
195 		for (i = 0; i < device->num_screens; i++) {
196 			struct kms_screen *screen = device->screens[i];
197 			const char *status = "disconnected";
198 
199 			if (screen->connected)
200 				status = "connected";
201 
202 			printf("  %u: %x\n", i, screen->id);
203 			printf("    Status: %s\n", status);
204 			printf("    Name: %s\n", screen->name);
205 			printf("    Resolution: %ux%u\n", screen->width,
206 			       screen->height);
207 		}
208 
209 		printf("Planes: %u\n", device->num_planes);
210 
211 		for (i = 0; i < device->num_planes; i++) {
212 			struct kms_plane *plane = device->planes[i];
213 			const char *type = NULL;
214 
215 			switch (plane->type) {
216 			case DRM_PLANE_TYPE_OVERLAY:
217 				type = "overlay";
218 				break;
219 
220 			case DRM_PLANE_TYPE_PRIMARY:
221 				type = "primary";
222 				break;
223 
224 			case DRM_PLANE_TYPE_CURSOR:
225 				type = "cursor";
226 				break;
227 			}
228 
229 			printf("  %u: %p\n", i, plane);
230 			printf("    ID: %x\n", plane->id);
231 			printf("    CRTC: %x\n", plane->crtc->id);
232 			printf("    Type: %x (%s)\n", plane->type, type);
233 		}
234 	}
235 
236 	if (use_cursor) {
237 		unsigned int x, y;
238 		uint32_t format;
239 
240 		plane = kms_device_find_plane_by_type(device,
241 						      DRM_PLANE_TYPE_CURSOR,
242 						      0);
243 		if (!plane) {
244 			fprintf(stderr, "no cursor plane found\n");
245 			return 1;
246 		}
247 
248 		format = choose_format(plane);
249 		if (!format) {
250 			fprintf(stderr, "no matching format found\n");
251 			return 1;
252 		}
253 
254 		cursor = kms_framebuffer_create(device, 32, 32, format);
255 		if (!cursor) {
256 			fprintf(stderr, "failed to create cursor buffer\n");
257 			return 1;
258 		}
259 
260 		prepare_framebuffer(cursor, false);
261 
262 		x = (device->screens[0]->width - cursor->width) / 2;
263 		y = (device->screens[0]->height - cursor->height) / 2;
264 
265 		kms_plane_set(plane, cursor, x, y);
266 	}
267 
268 	if (use_overlay) {
269 		uint32_t format;
270 
271 		plane = kms_device_find_plane_by_type(device,
272 						      DRM_PLANE_TYPE_OVERLAY,
273 						      0);
274 		if (!plane) {
275 			fprintf(stderr, "no overlay plane found\n");
276 			return 1;
277 		}
278 
279 		format = choose_format(plane);
280 		if (!format) {
281 			fprintf(stderr, "no matching format found\n");
282 			return 1;
283 		}
284 
285 		fb = kms_framebuffer_create(device, 320, 240, format);
286 		if (!fb)
287 			return 1;
288 
289 		prepare_framebuffer(fb, false);
290 
291 		kms_plane_set(plane, fb, 0, 0);
292 	}
293 
294 	if (use_primary) {
295 		unsigned int x, y;
296 		uint32_t format;
297 
298 		plane = kms_device_find_plane_by_type(device,
299 						      DRM_PLANE_TYPE_PRIMARY,
300 						      0);
301 		if (!plane) {
302 			fprintf(stderr, "no primary plane found\n");
303 			return 1;
304 		}
305 
306 		format = choose_format(plane);
307 		if (!format) {
308 			fprintf(stderr, "no matching format found\n");
309 			return 1;
310 		}
311 
312 		root = kms_framebuffer_create(device, 640, 480, format);
313 		if (!root)
314 			return 1;
315 
316 		prepare_framebuffer(root, true);
317 
318 		x = (device->screens[0]->width - root->width) / 2;
319 		y = (device->screens[0]->height - root->height) / 2;
320 
321 		kms_plane_set(plane, root, x, y);
322 	}
323 
324 	while (1) {
325 		struct timeval timeout = { 1, 0 };
326 		fd_set fds;
327 
328 		FD_ZERO(&fds);
329 		FD_SET(STDIN_FILENO, &fds);
330 
331 		err = select(STDIN_FILENO + 1, &fds, NULL, NULL, &timeout);
332 		if (err < 0) {
333 			fprintf(stderr, "select() failed: %m\n");
334 			break;
335 		}
336 
337 		/* timeout */
338 		if (err == 0)
339 			continue;
340 
341 		if (FD_ISSET(STDIN_FILENO, &fds))
342 			break;
343 	}
344 
345 	if (cursor)
346 		kms_framebuffer_free(cursor);
347 
348 	if (root)
349 		kms_framebuffer_free(root);
350 
351 	if (fb)
352 		kms_framebuffer_free(fb);
353 
354 	kms_device_close(device);
355 	close(fd);
356 
357 	return 0;
358 }
359