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