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 #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 #ifdef 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 
     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 
     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 
    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