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