modetest.c revision 694ef59532253727176ed0ce9077ae3ec41dd457
1/* 2 * DRM based mode setting test program 3 * Copyright 2008 Tungsten Graphics 4 * Jakob Bornecrantz <jakob@tungstengraphics.com> 5 * Copyright 2008 Intel Corporation 6 * Jesse Barnes <jesse.barnes@intel.com> 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included in 16 * all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 24 * IN THE SOFTWARE. 25 */ 26 27/* 28 * This fairly simple test program dumps output in a similar format to the 29 * "xrandr" tool everyone knows & loves. It's necessarily slightly different 30 * since the kernel separates outputs into encoder and connector structures, 31 * each with their own unique ID. The program also allows test testing of the 32 * memory management and mode setting APIs by allowing the user to specify a 33 * connector and mode to use for mode setting. If all works as expected, a 34 * blue background should be painted on the monitor attached to the specified 35 * connector after the selected mode is set. 36 * 37 * TODO: use cairo to write the mode info on the selected output once 38 * the mode has been programmed, along with possible test patterns. 39 */ 40#include "config.h" 41 42#include <assert.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <stdint.h> 46#include <unistd.h> 47#include <string.h> 48#include <errno.h> 49#include <sys/poll.h> 50#include <sys/time.h> 51 52#include "xf86drm.h" 53#include "xf86drmMode.h" 54#include "intel_bufmgr.h" 55#include "i915_drm.h" 56 57#ifdef HAVE_CAIRO 58#include <math.h> 59#include <cairo.h> 60#endif 61 62drmModeRes *resources; 63int fd, modes; 64 65#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 66 67struct type_name { 68 int type; 69 char *name; 70}; 71 72#define type_name_fn(res) \ 73char * res##_str(int type) { \ 74 int i; \ 75 for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ 76 if (res##_names[i].type == type) \ 77 return res##_names[i].name; \ 78 } \ 79 return "(invalid)"; \ 80} 81 82struct type_name encoder_type_names[] = { 83 { DRM_MODE_ENCODER_NONE, "none" }, 84 { DRM_MODE_ENCODER_DAC, "DAC" }, 85 { DRM_MODE_ENCODER_TMDS, "TMDS" }, 86 { DRM_MODE_ENCODER_LVDS, "LVDS" }, 87 { DRM_MODE_ENCODER_TVDAC, "TVDAC" }, 88}; 89 90type_name_fn(encoder_type) 91 92struct type_name connector_status_names[] = { 93 { DRM_MODE_CONNECTED, "connected" }, 94 { DRM_MODE_DISCONNECTED, "disconnected" }, 95 { DRM_MODE_UNKNOWNCONNECTION, "unknown" }, 96}; 97 98type_name_fn(connector_status) 99 100struct type_name connector_type_names[] = { 101 { DRM_MODE_CONNECTOR_Unknown, "unknown" }, 102 { DRM_MODE_CONNECTOR_VGA, "VGA" }, 103 { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, 104 { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, 105 { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, 106 { DRM_MODE_CONNECTOR_Composite, "composite" }, 107 { DRM_MODE_CONNECTOR_SVIDEO, "s-video" }, 108 { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 109 { DRM_MODE_CONNECTOR_Component, "component" }, 110 { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, 111 { DRM_MODE_CONNECTOR_DisplayPort, "displayport" }, 112 { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 113 { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 114}; 115 116type_name_fn(connector_type) 117 118void dump_encoders(void) 119{ 120 drmModeEncoder *encoder; 121 int i; 122 123 printf("Encoders:\n"); 124 printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); 125 for (i = 0; i < resources->count_encoders; i++) { 126 encoder = drmModeGetEncoder(fd, resources->encoders[i]); 127 128 if (!encoder) { 129 fprintf(stderr, "could not get encoder %i: %s\n", 130 resources->encoders[i], strerror(errno)); 131 continue; 132 } 133 printf("%d\t%d\t%s\t0x%08x\t0x%08x\n", 134 encoder->encoder_id, 135 encoder->crtc_id, 136 encoder_type_str(encoder->encoder_type), 137 encoder->possible_crtcs, 138 encoder->possible_clones); 139 drmModeFreeEncoder(encoder); 140 } 141 printf("\n"); 142} 143 144void dump_mode(drmModeModeInfo *mode) 145{ 146 printf(" %s %d %d %d %d %d %d %d %d %d\n", 147 mode->name, 148 mode->vrefresh, 149 mode->hdisplay, 150 mode->hsync_start, 151 mode->hsync_end, 152 mode->htotal, 153 mode->vdisplay, 154 mode->vsync_start, 155 mode->vsync_end, 156 mode->vtotal); 157} 158 159static void 160dump_props(drmModeConnector *connector) 161{ 162 drmModePropertyPtr props; 163 int i; 164 165 for (i = 0; i < connector->count_props; i++) { 166 props = drmModeGetProperty(fd, connector->props[i]); 167 printf("\t%s, flags %d\n", props->name, props->flags); 168 drmModeFreeProperty(props); 169 } 170} 171 172void dump_connectors(void) 173{ 174 drmModeConnector *connector; 175 int i, j; 176 177 printf("Connectors:\n"); 178 printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\tencoders\n"); 179 for (i = 0; i < resources->count_connectors; i++) { 180 connector = drmModeGetConnector(fd, resources->connectors[i]); 181 182 if (!connector) { 183 fprintf(stderr, "could not get connector %i: %s\n", 184 resources->connectors[i], strerror(errno)); 185 continue; 186 } 187 188 printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\t", 189 connector->connector_id, 190 connector->encoder_id, 191 connector_status_str(connector->connection), 192 connector_type_str(connector->connector_type), 193 connector->mmWidth, connector->mmHeight, 194 connector->count_modes); 195 196 for (j = 0; j < connector->count_encoders; j++) 197 printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]); 198 printf("\n"); 199 200 if (!connector->count_modes) 201 continue; 202 203 printf(" modes:\n"); 204 printf(" name refresh (Hz) hdisp hss hse htot vdisp " 205 "vss vse vtot)\n"); 206 for (j = 0; j < connector->count_modes; j++) 207 dump_mode(&connector->modes[j]); 208 209 drmModeFreeConnector(connector); 210 211 printf(" props:\n"); 212 dump_props(connector); 213 } 214 printf("\n"); 215} 216 217void dump_crtcs(void) 218{ 219 drmModeCrtc *crtc; 220 int i; 221 222 printf("CRTCs:\n"); 223 printf("id\tfb\tpos\tsize\n"); 224 for (i = 0; i < resources->count_crtcs; i++) { 225 crtc = drmModeGetCrtc(fd, resources->crtcs[i]); 226 227 if (!crtc) { 228 fprintf(stderr, "could not get crtc %i: %s\n", 229 resources->crtcs[i], strerror(errno)); 230 continue; 231 } 232 printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", 233 crtc->crtc_id, 234 crtc->buffer_id, 235 crtc->x, crtc->y, 236 crtc->width, crtc->height); 237 dump_mode(&crtc->mode); 238 239 drmModeFreeCrtc(crtc); 240 } 241 printf("\n"); 242} 243 244void dump_framebuffers(void) 245{ 246 drmModeFB *fb; 247 int i; 248 249 printf("Frame buffers:\n"); 250 printf("id\tsize\tpitch\n"); 251 for (i = 0; i < resources->count_fbs; i++) { 252 fb = drmModeGetFB(fd, resources->fbs[i]); 253 254 if (!fb) { 255 fprintf(stderr, "could not get fb %i: %s\n", 256 resources->fbs[i], strerror(errno)); 257 continue; 258 } 259 printf("%u\t(%ux%u)\t%u\n", 260 fb->fb_id, 261 fb->width, fb->height, 262 fb->pitch); 263 264 drmModeFreeFB(fb); 265 } 266 printf("\n"); 267} 268 269/* 270 * Mode setting with the kernel interfaces is a bit of a chore. 271 * First you have to find the connector in question and make sure the 272 * requested mode is available. 273 * Then you need to find the encoder attached to that connector so you 274 * can bind it with a free crtc. 275 */ 276struct connector { 277 uint32_t id; 278 char mode_str[64]; 279 drmModeModeInfo *mode; 280 drmModeEncoder *encoder; 281 int crtc; 282 unsigned int fb_id[2], current_fb_id; 283 struct timeval start; 284 285 int swap_count; 286}; 287 288static void 289connector_find_mode(struct connector *c) 290{ 291 drmModeConnector *connector; 292 int i, j; 293 294 /* First, find the connector & mode */ 295 c->mode = NULL; 296 for (i = 0; i < resources->count_connectors; i++) { 297 connector = drmModeGetConnector(fd, resources->connectors[i]); 298 299 if (!connector) { 300 fprintf(stderr, "could not get connector %i: %s\n", 301 resources->connectors[i], strerror(errno)); 302 drmModeFreeConnector(connector); 303 continue; 304 } 305 306 if (!connector->count_modes) { 307 drmModeFreeConnector(connector); 308 continue; 309 } 310 311 if (connector->connector_id != c->id) { 312 drmModeFreeConnector(connector); 313 continue; 314 } 315 316 for (j = 0; j < connector->count_modes; j++) { 317 c->mode = &connector->modes[j]; 318 if (!strcmp(c->mode->name, c->mode_str)) 319 break; 320 } 321 322 /* Found it, break out */ 323 if (c->mode) 324 break; 325 326 drmModeFreeConnector(connector); 327 } 328 329 if (!c->mode) { 330 fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str); 331 return; 332 } 333 334 /* Now get the encoder */ 335 for (i = 0; i < resources->count_encoders; i++) { 336 c->encoder = drmModeGetEncoder(fd, resources->encoders[i]); 337 338 if (!c->encoder) { 339 fprintf(stderr, "could not get encoder %i: %s\n", 340 resources->encoders[i], strerror(errno)); 341 drmModeFreeEncoder(c->encoder); 342 continue; 343 } 344 345 if (c->encoder->encoder_id == connector->encoder_id) 346 break; 347 348 drmModeFreeEncoder(c->encoder); 349 } 350 351 if (c->crtc == -1) 352 c->crtc = c->encoder->crtc_id; 353} 354 355#ifdef HAVE_CAIRO 356 357static int 358create_test_buffer(drm_intel_bufmgr *bufmgr, 359 int width, int height, int *stride_out, drm_intel_bo **bo_out) 360{ 361 drm_intel_bo *bo; 362 unsigned int *fb_ptr; 363 int size, i, stride; 364 div_t d; 365 cairo_surface_t *surface; 366 cairo_t *cr; 367 char buf[64]; 368 int x, y; 369 370 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); 371 stride = cairo_image_surface_get_stride(surface); 372 size = stride * height; 373 fb_ptr = (unsigned int *) cairo_image_surface_get_data(surface); 374 375 /* paint the buffer with colored tiles */ 376 for (i = 0; i < width * height; i++) { 377 d = div(i, width); 378 fb_ptr[i] = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6); 379 } 380 381 cr = cairo_create(surface); 382 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); 383 for (x = 0; x < width; x += 250) 384 for (y = 0; y < height; y += 250) { 385 cairo_set_operator(cr, CAIRO_OPERATOR_OVER); 386 cairo_move_to(cr, x, y - 20); 387 cairo_line_to(cr, x, y + 20); 388 cairo_move_to(cr, x - 20, y); 389 cairo_line_to(cr, x + 20, y); 390 cairo_new_sub_path(cr); 391 cairo_arc(cr, x, y, 10, 0, M_PI * 2); 392 cairo_set_line_width(cr, 4); 393 cairo_set_source_rgb(cr, 0, 0, 0); 394 cairo_stroke_preserve(cr); 395 cairo_set_source_rgb(cr, 1, 1, 1); 396 cairo_set_line_width(cr, 2); 397 cairo_stroke(cr); 398 snprintf(buf, sizeof buf, "%d, %d", x, y); 399 cairo_move_to(cr, x + 20, y + 20); 400 cairo_text_path(cr, buf); 401 cairo_set_source_rgb(cr, 0, 0, 0); 402 cairo_stroke_preserve(cr); 403 cairo_set_source_rgb(cr, 1, 1, 1); 404 cairo_fill(cr); 405 } 406 407 cairo_destroy(cr); 408 409 bo = drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 4096); 410 if (!bo) { 411 fprintf(stderr, "failed to alloc buffer: %s\n", 412 strerror(errno)); 413 return -1; 414 } 415 416 drm_intel_bo_subdata(bo, 0, size, fb_ptr); 417 418 cairo_surface_destroy(surface); 419 420 *bo_out = bo; 421 *stride_out = stride; 422 423 return 0; 424} 425 426#else 427 428static int 429create_test_buffer(drm_intel_bufmgr *bufmgr, 430 int width, int height, int *stride_out, drm_intel_bo **bo_out) 431{ 432 drm_intel_bo *bo; 433 unsigned int *fb_ptr; 434 int size, ret, i, stride; 435 div_t d; 436 437 /* Mode size at 32 bpp */ 438 stride = width * 4; 439 size = stride * height; 440 441 bo = drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 4096); 442 if (!bo) { 443 fprintf(stderr, "failed to alloc buffer: %s\n", 444 strerror(errno)); 445 return -1; 446 } 447 448 ret = drm_intel_gem_bo_map_gtt(bo); 449 if (ret) { 450 fprintf(stderr, "failed to GTT map buffer: %s\n", 451 strerror(errno)); 452 return -1; 453 } 454 455 fb_ptr = bo->virtual; 456 457 /* paint the buffer with colored tiles */ 458 for (i = 0; i < width * height; i++) { 459 d = div(i, width); 460 fb_ptr[i] = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6); 461 } 462 drm_intel_gem_bo_unmap_gtt(bo); 463 464 *bo_out = bo; 465 *stride_out = stride; 466 467 return 0; 468} 469 470#endif 471 472static int 473create_grey_buffer(drm_intel_bufmgr *bufmgr, 474 int width, int height, int *stride_out, drm_intel_bo **bo_out) 475{ 476 drm_intel_bo *bo; 477 int size, ret, stride; 478 479 /* Mode size at 32 bpp */ 480 stride = width * 4; 481 size = stride * height; 482 483 bo = drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 4096); 484 if (!bo) { 485 fprintf(stderr, "failed to alloc buffer: %s\n", 486 strerror(errno)); 487 return -1; 488 } 489 490 ret = drm_intel_gem_bo_map_gtt(bo); 491 if (ret) { 492 fprintf(stderr, "failed to GTT map buffer: %s\n", 493 strerror(errno)); 494 return -1; 495 } 496 497 memset(bo->virtual, 0x77, size); 498 drm_intel_gem_bo_unmap_gtt(bo); 499 500 *bo_out = bo; 501 *stride_out = stride; 502 503 return 0; 504} 505 506void 507page_flip_handler(int fd, unsigned int frame, 508 unsigned int sec, unsigned int usec, void *data) 509{ 510 struct connector *c; 511 unsigned int new_fb_id; 512 struct timeval end; 513 double t; 514 515 c = data; 516 if (c->current_fb_id == c->fb_id[0]) 517 new_fb_id = c->fb_id[1]; 518 else 519 new_fb_id = c->fb_id[0]; 520 521 drmModePageFlip(fd, c->crtc, new_fb_id, 522 DRM_MODE_PAGE_FLIP_EVENT, c); 523 c->current_fb_id = new_fb_id; 524 c->swap_count++; 525 if (c->swap_count == 60) { 526 gettimeofday(&end, NULL); 527 t = end.tv_sec + end.tv_usec * 1e-6 - 528 (c->start.tv_sec + c->start.tv_usec * 1e-6); 529 fprintf(stderr, "freq: %.02fHz\n", c->swap_count / t); 530 c->swap_count = 0; 531 c->start = end; 532 } 533} 534 535static void 536set_mode(struct connector *c, int count, int page_flip) 537{ 538 drm_intel_bufmgr *bufmgr; 539 drm_intel_bo *bo, *other_bo; 540 unsigned int fb_id, other_fb_id; 541 int i, ret, width, height, x, stride; 542 drmEventContext evctx; 543 544 width = 0; 545 height = 0; 546 for (i = 0; i < count; i++) { 547 connector_find_mode(&c[i]); 548 if (c[i].mode == NULL) 549 continue; 550 width += c[i].mode->hdisplay; 551 if (height < c[i].mode->vdisplay) 552 height = c[i].mode->vdisplay; 553 } 554 555 bufmgr = drm_intel_bufmgr_gem_init(fd, 2<<20); 556 if (!bufmgr) { 557 fprintf(stderr, "failed to init bufmgr: %s\n", strerror(errno)); 558 return; 559 } 560 561 if (create_test_buffer(bufmgr, width, height, &stride, &bo)) 562 return; 563 564 ret = drmModeAddFB(fd, width, height, 32, 32, stride, bo->handle, 565 &fb_id); 566 if (ret) { 567 fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 568 return; 569 } 570 571 x = 0; 572 for (i = 0; i < count; i++) { 573 if (c[i].mode == NULL) 574 continue; 575 576 printf("setting mode %s on connector %d, crtc %d\n", 577 c[i].mode_str, c[i].id, c[i].crtc); 578 579 ret = drmModeSetCrtc(fd, c[i].crtc, fb_id, x, 0, 580 &c[i].id, 1, c[i].mode); 581 x += c[i].mode->hdisplay; 582 583 if (ret) { 584 fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); 585 return; 586 } 587 } 588 589 if (!page_flip) 590 return; 591 592 if (create_grey_buffer(bufmgr, width, height, &stride, &other_bo)) 593 return; 594 595 ret = drmModeAddFB(fd, width, height, 32, 32, stride, other_bo->handle, 596 &other_fb_id); 597 if (ret) { 598 fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 599 return; 600 } 601 602 for (i = 0; i < count; i++) { 603 if (c[i].mode == NULL) 604 continue; 605 606 drmModePageFlip(fd, c[i].crtc, other_fb_id, 607 DRM_MODE_PAGE_FLIP_EVENT, &c[i]); 608 gettimeofday(&c[i].start, NULL); 609 c[i].swap_count = 0; 610 c[i].fb_id[0] = fb_id; 611 c[i].fb_id[1] = other_fb_id; 612 c[i].current_fb_id = fb_id; 613 } 614 615 memset(&evctx, 0, sizeof evctx); 616 evctx.version = DRM_EVENT_CONTEXT_VERSION; 617 evctx.vblank_handler = NULL; 618 evctx.page_flip_handler = page_flip_handler; 619 620 while (1) { 621 struct pollfd pfd[2]; 622 623 pfd[0].fd = 0; 624 pfd[0].events = POLLIN; 625 pfd[1].fd = fd; 626 pfd[1].events = POLLIN; 627 628 if (poll(pfd, 2, -1) < 0) { 629 fprintf(stderr, "poll error\n"); 630 break; 631 } 632 633 if (pfd[0].revents) 634 break; 635 636 drmHandleEvent(fd, &evctx); 637 } 638} 639 640extern char *optarg; 641extern int optind, opterr, optopt; 642static char optstr[] = "ecpmfs:v"; 643 644void usage(char *name) 645{ 646 fprintf(stderr, "usage: %s [-ecpmf]\n", name); 647 fprintf(stderr, "\t-e\tlist encoders\n"); 648 fprintf(stderr, "\t-c\tlist connectors\n"); 649 fprintf(stderr, "\t-p\tlist CRTCs (pipes)\n"); 650 fprintf(stderr, "\t-m\tlist modes\n"); 651 fprintf(stderr, "\t-f\tlist framebuffers\n"); 652 fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); 653 fprintf(stderr, "\t-s <connector_id>:<mode>\tset a mode\n"); 654 fprintf(stderr, "\t-s <connector_id>@<crtc_id>:<mode>\tset a mode\n"); 655 fprintf(stderr, "\n\tDefault is to dump all info.\n"); 656 exit(0); 657} 658 659#define dump_resource(res) if (res) dump_##res() 660 661static int page_flipping_supported(int fd) 662{ 663 int ret, value; 664 struct drm_i915_getparam gp; 665 666 gp.param = I915_PARAM_HAS_PAGEFLIPPING; 667 gp.value = &value; 668 669 ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp)); 670 if (ret) { 671 fprintf(stderr, "drm_i915_getparam: %m\n"); 672 return 0; 673 } 674 675 return *gp.value; 676} 677 678int main(int argc, char **argv) 679{ 680 int c; 681 int encoders = 0, connectors = 0, crtcs = 0, framebuffers = 0; 682 int test_vsync = 0; 683 char *modules[] = { "i915", "radeon", "nouveau" }; 684 char *modeset = NULL; 685 int i, count = 0; 686 struct connector con_args[2]; 687 688 opterr = 0; 689 while ((c = getopt(argc, argv, optstr)) != -1) { 690 switch (c) { 691 case 'e': 692 encoders = 1; 693 break; 694 case 'c': 695 connectors = 1; 696 break; 697 case 'p': 698 crtcs = 1; 699 break; 700 case 'm': 701 modes = 1; 702 break; 703 case 'f': 704 framebuffers = 1; 705 break; 706 case 'v': 707 test_vsync = 1; 708 break; 709 case 's': 710 modeset = strdup(optarg); 711 con_args[count].crtc = -1; 712 if (sscanf(optarg, "%d:%64s", 713 &con_args[count].id, 714 con_args[count].mode_str) != 2 && 715 sscanf(optarg, "%d@%d:%64s", 716 &con_args[count].id, 717 &con_args[count].crtc, 718 con_args[count].mode_str) != 3) 719 usage(argv[0]); 720 count++; 721 break; 722 default: 723 usage(argv[0]); 724 break; 725 } 726 } 727 728 if (argc == 1) 729 encoders = connectors = crtcs = modes = framebuffers = 1; 730 731 for (i = 0; i < ARRAY_SIZE(modules); i++) { 732 printf("trying to load module %s...", modules[i]); 733 fd = drmOpen(modules[i], NULL); 734 if (fd < 0) { 735 printf("failed.\n"); 736 } else { 737 printf("success.\n"); 738 break; 739 } 740 } 741 742 if (test_vsync && !page_flipping_supported(fd)) { 743 fprintf(stderr, "page flipping not supported by drm.\n"); 744 return -1; 745 } 746 747 if (i == ARRAY_SIZE(modules)) { 748 fprintf(stderr, "failed to load any modules, aborting.\n"); 749 return -1; 750 } 751 752 resources = drmModeGetResources(fd); 753 if (!resources) { 754 fprintf(stderr, "drmModeGetResources failed: %s\n", 755 strerror(errno)); 756 drmClose(fd); 757 return 1; 758 } 759 760 dump_resource(encoders); 761 dump_resource(connectors); 762 dump_resource(crtcs); 763 dump_resource(framebuffers); 764 765 if (count > 0) { 766 set_mode(con_args, count, test_vsync); 767 getchar(); 768 } 769 770 drmModeFreeResources(resources); 771 772 return 0; 773} 774