• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifdef HAVE_SYS_SELECT_H
36 #include <sys/select.h>
37 #endif
38 
39 #include <drm_fourcc.h>
40 #include "xf86drm.h"
41 
42 #include "util/common.h"
43 #include "libkms-test.h"
44 
45 static const uint32_t formats[] = {
46 	DRM_FORMAT_XRGB8888,
47 	DRM_FORMAT_XBGR8888,
48 	DRM_FORMAT_RGBA8888,
49 };
50 
choose_format(struct kms_plane * plane)51 static uint32_t choose_format(struct kms_plane *plane)
52 {
53 	unsigned int i;
54 
55 	for (i = 0; i < ARRAY_SIZE(formats); i++)
56 		if (kms_plane_supports_format(plane, formats[i]))
57 			return formats[i];
58 
59 	return 0;
60 }
61 
prepare_framebuffer(struct kms_framebuffer * fb,bool invert)62 static void prepare_framebuffer(struct kms_framebuffer *fb, bool invert)
63 {
64 	const unsigned int block_size = 16;
65 	uint32_t colors[2];
66 	unsigned int i, j;
67 	uint32_t *buf;
68 	void *ptr;
69 	int err;
70 
71 	switch (fb->format) {
72 	case DRM_FORMAT_XRGB8888:
73 		printf("using XRGB8888 format\n");
74 		           /* XXRRGGBB */
75 		colors[0] = 0xffff0000;
76 		colors[1] = 0xff0000ff;
77 		break;
78 
79 	case DRM_FORMAT_XBGR8888:
80 		printf("using XBGR8888 format\n");
81 		           /* XXBBGGRR */
82 		colors[0] = 0xff0000ff;
83 		colors[1] = 0xffff0000;
84 		break;
85 
86 	case DRM_FORMAT_RGBA8888:
87 		printf("using RGBA8888 format\n");
88 		           /* RRGGBBAA */
89 		colors[0] = 0xff0000ff;
90 		colors[1] = 0x0000ffff;
91 		break;
92 
93 	default:
94 		colors[0] = 0xffffffff;
95 		colors[1] = 0xffffffff;
96 		break;
97 	}
98 
99 	err = kms_framebuffer_map(fb, &ptr);
100 	if (err < 0) {
101 		fprintf(stderr, "kms_framebuffer_map() failed: %s\n",
102 			strerror(-err));
103 		return;
104 	}
105 
106 	buf = ptr;
107 
108 	for (j = 0; j < fb->height; j++) {
109 		for (i = 0; i < fb->width; i++) {
110 			unsigned int color = (j / block_size) ^
111 					     (i / block_size);
112 
113 			if (invert)
114 				color ^= color;
115 
116 			*buf++ = colors[color & 1];
117 		}
118 	}
119 
120 	kms_framebuffer_unmap(fb);
121 }
122 
main(int argc,char * argv[])123 int main(int argc, char *argv[])
124 {
125 	static const char opts[] = "chopv";
126 	static struct option options[] = {
127 		{ "cursor", 0, 0, 'c' },
128 		{ "help", 0, 0, 'h' },
129 		{ "overlay", 0, 0, 'o' },
130 		{ "primary", 0, 0, 'p' },
131 		{ "verbose", 0, 0, 'v' },
132 		{ 0, 0, 0, 0 },
133 	};
134 	struct kms_framebuffer *cursor = NULL;
135 	struct kms_framebuffer *root = NULL;
136 	struct kms_framebuffer *fb = NULL;
137 	struct kms_device *device;
138 	bool use_overlay = false;
139 	bool use_primary = false;
140 	struct kms_plane *plane;
141 	bool use_cursor = false;
142 	bool verbose = false;
143 	unsigned int i;
144 	int opt, idx;
145 	int fd, err;
146 
147 	while ((opt = getopt_long(argc, argv, opts, options, &idx)) != -1) {
148 		switch (opt) {
149 		case 'c':
150 			use_cursor = true;
151 			break;
152 
153 		case 'h':
154 			break;
155 
156 		case 'o':
157 			use_overlay = true;
158 			break;
159 
160 		case 'p':
161 			use_primary = true;
162 			break;
163 
164 		case 'v':
165 			verbose = true;
166 			break;
167 
168 		default:
169 			printf("unknown option \"%c\"\n", opt);
170 			return 1;
171 		}
172 	}
173 
174 	if (optind >= argc) {
175 		fprintf(stderr, "usage: %s [options] DEVICE\n", argv[0]);
176 		return 1;
177 	}
178 
179 	fd = open(argv[optind], O_RDWR);
180 	if (fd < 0) {
181 		fprintf(stderr, "open() failed: %m\n");
182 		return 1;
183 	}
184 
185 	err = drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
186 	if (err < 0) {
187 		fprintf(stderr, "drmSetClientCap() failed: %d\n", err);
188 		return 1;
189 	}
190 
191 	device = kms_device_open(fd);
192 	if (!device)
193 		return 1;
194 
195 	if (verbose) {
196 		printf("Screens: %u\n", device->num_screens);
197 
198 		for (i = 0; i < device->num_screens; i++) {
199 			struct kms_screen *screen = device->screens[i];
200 			const char *status = "disconnected";
201 
202 			if (screen->connected)
203 				status = "connected";
204 
205 			printf("  %u: %x\n", i, screen->id);
206 			printf("    Status: %s\n", status);
207 			printf("    Name: %s\n", screen->name);
208 			printf("    Resolution: %ux%u\n", screen->width,
209 			       screen->height);
210 		}
211 
212 		printf("Planes: %u\n", device->num_planes);
213 
214 		for (i = 0; i < device->num_planes; i++) {
215 			const char *type = NULL;
216 
217 			plane = device->planes[i];
218 			switch (plane->type) {
219 			case DRM_PLANE_TYPE_OVERLAY:
220 				type = "overlay";
221 				break;
222 
223 			case DRM_PLANE_TYPE_PRIMARY:
224 				type = "primary";
225 				break;
226 
227 			case DRM_PLANE_TYPE_CURSOR:
228 				type = "cursor";
229 				break;
230 			}
231 
232 			printf("  %u: %p\n", i, plane);
233 			printf("    ID: %x\n", plane->id);
234 			printf("    CRTC: %x\n", plane->crtc->id);
235 			printf("    Type: %x (%s)\n", plane->type, type);
236 		}
237 	}
238 
239 	if (use_cursor) {
240 		unsigned int x, y;
241 		uint32_t format;
242 
243 		plane = kms_device_find_plane_by_type(device,
244 						      DRM_PLANE_TYPE_CURSOR,
245 						      0);
246 		if (!plane) {
247 			fprintf(stderr, "no cursor plane found\n");
248 			return 1;
249 		}
250 
251 		format = choose_format(plane);
252 		if (!format) {
253 			fprintf(stderr, "no matching format found\n");
254 			return 1;
255 		}
256 
257 		cursor = kms_framebuffer_create(device, 32, 32, format);
258 		if (!cursor) {
259 			fprintf(stderr, "failed to create cursor buffer\n");
260 			return 1;
261 		}
262 
263 		prepare_framebuffer(cursor, false);
264 
265 		x = (device->screens[0]->width - cursor->width) / 2;
266 		y = (device->screens[0]->height - cursor->height) / 2;
267 
268 		kms_plane_set(plane, cursor, x, y);
269 	}
270 
271 	if (use_overlay) {
272 		uint32_t format;
273 
274 		plane = kms_device_find_plane_by_type(device,
275 						      DRM_PLANE_TYPE_OVERLAY,
276 						      0);
277 		if (!plane) {
278 			fprintf(stderr, "no overlay plane found\n");
279 			return 1;
280 		}
281 
282 		format = choose_format(plane);
283 		if (!format) {
284 			fprintf(stderr, "no matching format found\n");
285 			return 1;
286 		}
287 
288 		fb = kms_framebuffer_create(device, 320, 240, format);
289 		if (!fb)
290 			return 1;
291 
292 		prepare_framebuffer(fb, false);
293 
294 		kms_plane_set(plane, fb, 0, 0);
295 	}
296 
297 	if (use_primary) {
298 		unsigned int x, y;
299 		uint32_t format;
300 
301 		plane = kms_device_find_plane_by_type(device,
302 						      DRM_PLANE_TYPE_PRIMARY,
303 						      0);
304 		if (!plane) {
305 			fprintf(stderr, "no primary plane found\n");
306 			return 1;
307 		}
308 
309 		format = choose_format(plane);
310 		if (!format) {
311 			fprintf(stderr, "no matching format found\n");
312 			return 1;
313 		}
314 
315 		root = kms_framebuffer_create(device, 640, 480, format);
316 		if (!root)
317 			return 1;
318 
319 		prepare_framebuffer(root, true);
320 
321 		x = (device->screens[0]->width - root->width) / 2;
322 		y = (device->screens[0]->height - root->height) / 2;
323 
324 		kms_plane_set(plane, root, x, y);
325 	}
326 
327 	while (1) {
328 		struct timeval timeout = { 1, 0 };
329 		fd_set fds;
330 
331 		FD_ZERO(&fds);
332 		FD_SET(STDIN_FILENO, &fds);
333 
334 		err = select(STDIN_FILENO + 1, &fds, NULL, NULL, &timeout);
335 		if (err < 0) {
336 			fprintf(stderr, "select() failed: %m\n");
337 			break;
338 		}
339 
340 		/* timeout */
341 		if (err == 0)
342 			continue;
343 
344 		if (FD_ISSET(STDIN_FILENO, &fds))
345 			break;
346 	}
347 
348 	if (cursor)
349 		kms_framebuffer_free(cursor);
350 
351 	if (root)
352 		kms_framebuffer_free(root);
353 
354 	if (fb)
355 		kms_framebuffer_free(fb);
356 
357 	kms_device_close(device);
358 	close(fd);
359 
360 	return 0;
361 }
362