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