Home | History | Annotate | Download | only in kms
      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 
     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 
     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 
    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