modetest.c revision d049871a
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 { DRM_MODE_CONNECTOR_TV, "TV" }, 115 { DRM_MODE_CONNECTOR_eDP, "embedded displayport" }, 116}; 117 118type_name_fn(connector_type) 119 120void dump_encoders(void) 121{ 122 drmModeEncoder *encoder; 123 int i; 124 125 printf("Encoders:\n"); 126 printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); 127 for (i = 0; i < resources->count_encoders; i++) { 128 encoder = drmModeGetEncoder(fd, resources->encoders[i]); 129 130 if (!encoder) { 131 fprintf(stderr, "could not get encoder %i: %s\n", 132 resources->encoders[i], strerror(errno)); 133 continue; 134 } 135 printf("%d\t%d\t%s\t0x%08x\t0x%08x\n", 136 encoder->encoder_id, 137 encoder->crtc_id, 138 encoder_type_str(encoder->encoder_type), 139 encoder->possible_crtcs, 140 encoder->possible_clones); 141 drmModeFreeEncoder(encoder); 142 } 143 printf("\n"); 144} 145 146void dump_mode(drmModeModeInfo *mode) 147{ 148 printf(" %s %d %d %d %d %d %d %d %d %d\n", 149 mode->name, 150 mode->vrefresh, 151 mode->hdisplay, 152 mode->hsync_start, 153 mode->hsync_end, 154 mode->htotal, 155 mode->vdisplay, 156 mode->vsync_start, 157 mode->vsync_end, 158 mode->vtotal); 159} 160 161static void 162dump_props(drmModeConnector *connector) 163{ 164 drmModePropertyPtr props; 165 int i; 166 167 for (i = 0; i < connector->count_props; i++) { 168 props = drmModeGetProperty(fd, connector->props[i]); 169 printf("\t%s, flags %d\n", props->name, props->flags); 170 drmModeFreeProperty(props); 171 } 172} 173 174void dump_connectors(void) 175{ 176 drmModeConnector *connector; 177 int i, j; 178 179 printf("Connectors:\n"); 180 printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\tencoders\n"); 181 for (i = 0; i < resources->count_connectors; i++) { 182 connector = drmModeGetConnector(fd, resources->connectors[i]); 183 184 if (!connector) { 185 fprintf(stderr, "could not get connector %i: %s\n", 186 resources->connectors[i], strerror(errno)); 187 continue; 188 } 189 190 printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\t", 191 connector->connector_id, 192 connector->encoder_id, 193 connector_status_str(connector->connection), 194 connector_type_str(connector->connector_type), 195 connector->mmWidth, connector->mmHeight, 196 connector->count_modes); 197 198 for (j = 0; j < connector->count_encoders; j++) 199 printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]); 200 printf("\n"); 201 202 if (!connector->count_modes) 203 continue; 204 205 printf(" modes:\n"); 206 printf(" name refresh (Hz) hdisp hss hse htot vdisp " 207 "vss vse vtot)\n"); 208 for (j = 0; j < connector->count_modes; j++) 209 dump_mode(&connector->modes[j]); 210 211 printf(" props:\n"); 212 dump_props(connector); 213 214 drmModeFreeConnector(connector); 215 } 216 printf("\n"); 217} 218 219void dump_crtcs(void) 220{ 221 drmModeCrtc *crtc; 222 int i; 223 224 printf("CRTCs:\n"); 225 printf("id\tfb\tpos\tsize\n"); 226 for (i = 0; i < resources->count_crtcs; i++) { 227 crtc = drmModeGetCrtc(fd, resources->crtcs[i]); 228 229 if (!crtc) { 230 fprintf(stderr, "could not get crtc %i: %s\n", 231 resources->crtcs[i], strerror(errno)); 232 continue; 233 } 234 printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", 235 crtc->crtc_id, 236 crtc->buffer_id, 237 crtc->x, crtc->y, 238 crtc->width, crtc->height); 239 dump_mode(&crtc->mode); 240 241 drmModeFreeCrtc(crtc); 242 } 243 printf("\n"); 244} 245 246void dump_framebuffers(void) 247{ 248 drmModeFB *fb; 249 int i; 250 251 printf("Frame buffers:\n"); 252 printf("id\tsize\tpitch\n"); 253 for (i = 0; i < resources->count_fbs; i++) { 254 fb = drmModeGetFB(fd, resources->fbs[i]); 255 256 if (!fb) { 257 fprintf(stderr, "could not get fb %i: %s\n", 258 resources->fbs[i], strerror(errno)); 259 continue; 260 } 261 printf("%u\t(%ux%u)\t%u\n", 262 fb->fb_id, 263 fb->width, fb->height, 264 fb->pitch); 265 266 drmModeFreeFB(fb); 267 } 268 printf("\n"); 269} 270 271/* 272 * Mode setting with the kernel interfaces is a bit of a chore. 273 * First you have to find the connector in question and make sure the 274 * requested mode is available. 275 * Then you need to find the encoder attached to that connector so you 276 * can bind it with a free crtc. 277 */ 278struct connector { 279 uint32_t id; 280 char mode_str[64]; 281 drmModeModeInfo *mode; 282 drmModeEncoder *encoder; 283 int crtc; 284 unsigned int fb_id[2], current_fb_id; 285 struct timeval start; 286 287 int swap_count; 288}; 289 290static void 291connector_find_mode(struct connector *c) 292{ 293 drmModeConnector *connector; 294 int i, j; 295 296 /* First, find the connector & mode */ 297 c->mode = NULL; 298 for (i = 0; i < resources->count_connectors; i++) { 299 connector = drmModeGetConnector(fd, resources->connectors[i]); 300 301 if (!connector) { 302 fprintf(stderr, "could not get connector %i: %s\n", 303 resources->connectors[i], strerror(errno)); 304 drmModeFreeConnector(connector); 305 continue; 306 } 307 308 if (!connector->count_modes) { 309 drmModeFreeConnector(connector); 310 continue; 311 } 312 313 if (connector->connector_id != c->id) { 314 drmModeFreeConnector(connector); 315 continue; 316 } 317 318 for (j = 0; j < connector->count_modes; j++) { 319 c->mode = &connector->modes[j]; 320 if (!strcmp(c->mode->name, c->mode_str)) 321 break; 322 } 323 324 /* Found it, break out */ 325 if (c->mode) 326 break; 327 328 drmModeFreeConnector(connector); 329 } 330 331 if (!c->mode) { 332 fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str); 333 return; 334 } 335 336 /* Now get the encoder */ 337 for (i = 0; i < resources->count_encoders; i++) { 338 c->encoder = drmModeGetEncoder(fd, resources->encoders[i]); 339 340 if (!c->encoder) { 341 fprintf(stderr, "could not get encoder %i: %s\n", 342 resources->encoders[i], strerror(errno)); 343 drmModeFreeEncoder(c->encoder); 344 continue; 345 } 346 347 if (c->encoder->encoder_id == connector->encoder_id) 348 break; 349 350 drmModeFreeEncoder(c->encoder); 351 } 352 353 if (c->crtc == -1) 354 c->crtc = c->encoder->crtc_id; 355} 356 357static drm_intel_bo * 358allocate_buffer(drm_intel_bufmgr *bufmgr, 359 int width, int height, int *stride) 360{ 361 int size; 362 363 /* Scan-out has a 64 byte alignment restriction */ 364 size = (width + 63) & -64; 365 *stride = size; 366 size *= height; 367 368 return drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 0); 369} 370 371static void 372make_pwetty(drm_intel_bo *bo, int width, int height, int stride) 373{ 374#ifdef HAVE_CAIRO 375 cairo_surface_t *surface; 376 cairo_t *cr; 377 int x, y; 378 379 surface = cairo_image_surface_create_for_data(bo->virtual, 380 CAIRO_FORMAT_ARGB32, 381 width, height, 382 stride); 383 cr = cairo_create(surface); 384 cairo_surface_destroy(surface); 385 386 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); 387 for (x = 0; x < width; x += 250) 388 for (y = 0; y < height; y += 250) { 389 char buf[64]; 390 391 cairo_move_to(cr, x, y - 20); 392 cairo_line_to(cr, x, y + 20); 393 cairo_move_to(cr, x - 20, y); 394 cairo_line_to(cr, x + 20, y); 395 cairo_new_sub_path(cr); 396 cairo_arc(cr, x, y, 10, 0, M_PI * 2); 397 cairo_set_line_width(cr, 4); 398 cairo_set_source_rgb(cr, 0, 0, 0); 399 cairo_stroke_preserve(cr); 400 cairo_set_source_rgb(cr, 1, 1, 1); 401 cairo_set_line_width(cr, 2); 402 cairo_stroke(cr); 403 404 snprintf(buf, sizeof buf, "%d, %d", x, y); 405 cairo_move_to(cr, x + 20, y + 20); 406 cairo_text_path(cr, buf); 407 cairo_set_source_rgb(cr, 0, 0, 0); 408 cairo_stroke_preserve(cr); 409 cairo_set_source_rgb(cr, 1, 1, 1); 410 cairo_fill(cr); 411 } 412 413 cairo_destroy(cr); 414#endif 415} 416 417static int 418create_test_buffer(drm_intel_bufmgr *bufmgr, 419 int width, int height, int *stride_out, drm_intel_bo **bo_out) 420{ 421 drm_intel_bo *bo; 422 int ret, i, j, stride; 423 424 bo = allocate_buffer(bufmgr, width, height, &stride); 425 if (!bo) { 426 fprintf(stderr, "failed to alloc buffer: %s\n", 427 strerror(errno)); 428 return -1; 429 } 430 431 ret = drm_intel_gem_bo_map_gtt(bo); 432 if (ret) { 433 fprintf(stderr, "failed to GTT map buffer: %s\n", 434 strerror(errno)); 435 return -1; 436 } 437 438 /* paint the buffer with colored tiles */ 439 for (j = 0; j < height; j++) { 440 uint32_t *fb_ptr = (uint32_t*)((char*)bo->virtual + j * stride); 441 for (i = 0; i < width; i++) { 442 div_t d = div(i, width); 443 fb_ptr[i] = 444 0x00130502 * (d.quot >> 6) + 445 0x000a1120 * (d.rem >> 6); 446 } 447 } 448 449 make_pwetty(bo, width, height, stride); 450 451 drm_intel_gem_bo_unmap_gtt(bo); 452 453 *bo_out = bo; 454 *stride_out = stride; 455 return 0; 456} 457 458static int 459create_grey_buffer(drm_intel_bufmgr *bufmgr, 460 int width, int height, int *stride_out, drm_intel_bo **bo_out) 461{ 462 drm_intel_bo *bo; 463 int size, ret, stride; 464 465 /* Mode size at 32 bpp */ 466 stride = width * 4; 467 size = stride * height; 468 469 bo = drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 4096); 470 if (!bo) { 471 fprintf(stderr, "failed to alloc buffer: %s\n", 472 strerror(errno)); 473 return -1; 474 } 475 476 ret = drm_intel_gem_bo_map_gtt(bo); 477 if (ret) { 478 fprintf(stderr, "failed to GTT map buffer: %s\n", 479 strerror(errno)); 480 return -1; 481 } 482 483 memset(bo->virtual, 0x77, size); 484 drm_intel_gem_bo_unmap_gtt(bo); 485 486 *bo_out = bo; 487 *stride_out = stride; 488 489 return 0; 490} 491 492void 493page_flip_handler(int fd, unsigned int frame, 494 unsigned int sec, unsigned int usec, void *data) 495{ 496 struct connector *c; 497 unsigned int new_fb_id; 498 struct timeval end; 499 double t; 500 501 c = data; 502 if (c->current_fb_id == c->fb_id[0]) 503 new_fb_id = c->fb_id[1]; 504 else 505 new_fb_id = c->fb_id[0]; 506 507 drmModePageFlip(fd, c->crtc, new_fb_id, 508 DRM_MODE_PAGE_FLIP_EVENT, c); 509 c->current_fb_id = new_fb_id; 510 c->swap_count++; 511 if (c->swap_count == 60) { 512 gettimeofday(&end, NULL); 513 t = end.tv_sec + end.tv_usec * 1e-6 - 514 (c->start.tv_sec + c->start.tv_usec * 1e-6); 515 fprintf(stderr, "freq: %.02fHz\n", c->swap_count / t); 516 c->swap_count = 0; 517 c->start = end; 518 } 519} 520 521static void 522set_mode(struct connector *c, int count, int page_flip) 523{ 524 drm_intel_bufmgr *bufmgr; 525 drm_intel_bo *bo, *other_bo; 526 unsigned int fb_id, other_fb_id; 527 int i, ret, width, height, x, stride; 528 drmEventContext evctx; 529 530 width = 0; 531 height = 0; 532 for (i = 0; i < count; i++) { 533 connector_find_mode(&c[i]); 534 if (c[i].mode == NULL) 535 continue; 536 width += c[i].mode->hdisplay; 537 if (height < c[i].mode->vdisplay) 538 height = c[i].mode->vdisplay; 539 } 540 541 bufmgr = drm_intel_bufmgr_gem_init(fd, 2<<20); 542 if (!bufmgr) { 543 fprintf(stderr, "failed to init bufmgr: %s\n", strerror(errno)); 544 return; 545 } 546 547 if (create_test_buffer(bufmgr, width, height, &stride, &bo)) 548 return; 549 550 ret = drmModeAddFB(fd, width, height, 32, 32, stride, bo->handle, 551 &fb_id); 552 if (ret) { 553 fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 554 return; 555 } 556 557 x = 0; 558 for (i = 0; i < count; i++) { 559 if (c[i].mode == NULL) 560 continue; 561 562 printf("setting mode %s on connector %d, crtc %d\n", 563 c[i].mode_str, c[i].id, c[i].crtc); 564 565 ret = drmModeSetCrtc(fd, c[i].crtc, fb_id, x, 0, 566 &c[i].id, 1, c[i].mode); 567 x += c[i].mode->hdisplay; 568 569 if (ret) { 570 fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); 571 return; 572 } 573 } 574 575 if (!page_flip) 576 return; 577 578 if (create_grey_buffer(bufmgr, width, height, &stride, &other_bo)) 579 return; 580 581 ret = drmModeAddFB(fd, width, height, 32, 32, stride, other_bo->handle, 582 &other_fb_id); 583 if (ret) { 584 fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 585 return; 586 } 587 588 for (i = 0; i < count; i++) { 589 if (c[i].mode == NULL) 590 continue; 591 592 drmModePageFlip(fd, c[i].crtc, other_fb_id, 593 DRM_MODE_PAGE_FLIP_EVENT, &c[i]); 594 gettimeofday(&c[i].start, NULL); 595 c[i].swap_count = 0; 596 c[i].fb_id[0] = fb_id; 597 c[i].fb_id[1] = other_fb_id; 598 c[i].current_fb_id = fb_id; 599 } 600 601 memset(&evctx, 0, sizeof evctx); 602 evctx.version = DRM_EVENT_CONTEXT_VERSION; 603 evctx.vblank_handler = NULL; 604 evctx.page_flip_handler = page_flip_handler; 605 606 while (1) { 607#if 0 608 struct pollfd pfd[2]; 609 610 pfd[0].fd = 0; 611 pfd[0].events = POLLIN; 612 pfd[1].fd = fd; 613 pfd[1].events = POLLIN; 614 615 if (poll(pfd, 2, -1) < 0) { 616 fprintf(stderr, "poll error\n"); 617 break; 618 } 619 620 if (pfd[0].revents) 621 break; 622#else 623 struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; 624 fd_set fds; 625 int ret; 626 627 FD_ZERO(&fds); 628 FD_SET(0, &fds); 629 FD_SET(fd, &fds); 630 ret = select(fd + 1, &fds, NULL, NULL, &timeout); 631 632 if (ret <= 0) { 633 fprintf(stderr, "select timed out or error (ret %d)\n", 634 ret); 635 continue; 636 } else if (FD_ISSET(0, &fds)) { 637 break; 638 } 639#endif 640 641 drmHandleEvent(fd, &evctx); 642 } 643} 644 645extern char *optarg; 646extern int optind, opterr, optopt; 647static char optstr[] = "ecpmfs:v"; 648 649void usage(char *name) 650{ 651 fprintf(stderr, "usage: %s [-ecpmf]\n", name); 652 fprintf(stderr, "\t-e\tlist encoders\n"); 653 fprintf(stderr, "\t-c\tlist connectors\n"); 654 fprintf(stderr, "\t-p\tlist CRTCs (pipes)\n"); 655 fprintf(stderr, "\t-m\tlist modes\n"); 656 fprintf(stderr, "\t-f\tlist framebuffers\n"); 657 fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); 658 fprintf(stderr, "\t-s <connector_id>:<mode>\tset a mode\n"); 659 fprintf(stderr, "\t-s <connector_id>@<crtc_id>:<mode>\tset a mode\n"); 660 fprintf(stderr, "\n\tDefault is to dump all info.\n"); 661 exit(0); 662} 663 664#define dump_resource(res) if (res) dump_##res() 665 666static int page_flipping_supported(int fd) 667{ 668 int ret, value; 669 struct drm_i915_getparam gp; 670 671 gp.param = I915_PARAM_HAS_PAGEFLIPPING; 672 gp.value = &value; 673 674 ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp)); 675 if (ret) { 676 fprintf(stderr, "drm_i915_getparam: %m\n"); 677 return 0; 678 } 679 680 return *gp.value; 681} 682 683int main(int argc, char **argv) 684{ 685 int c; 686 int encoders = 0, connectors = 0, crtcs = 0, framebuffers = 0; 687 int test_vsync = 0; 688 char *modules[] = { "i915", "radeon", "nouveau" }; 689 char *modeset = NULL; 690 int i, count = 0; 691 struct connector con_args[2]; 692 693 opterr = 0; 694 while ((c = getopt(argc, argv, optstr)) != -1) { 695 switch (c) { 696 case 'e': 697 encoders = 1; 698 break; 699 case 'c': 700 connectors = 1; 701 break; 702 case 'p': 703 crtcs = 1; 704 break; 705 case 'm': 706 modes = 1; 707 break; 708 case 'f': 709 framebuffers = 1; 710 break; 711 case 'v': 712 test_vsync = 1; 713 break; 714 case 's': 715 modeset = strdup(optarg); 716 con_args[count].crtc = -1; 717 if (sscanf(optarg, "%d:%64s", 718 &con_args[count].id, 719 con_args[count].mode_str) != 2 && 720 sscanf(optarg, "%d@%d:%64s", 721 &con_args[count].id, 722 &con_args[count].crtc, 723 con_args[count].mode_str) != 3) 724 usage(argv[0]); 725 count++; 726 break; 727 default: 728 usage(argv[0]); 729 break; 730 } 731 } 732 733 if (argc == 1) 734 encoders = connectors = crtcs = modes = framebuffers = 1; 735 736 for (i = 0; i < ARRAY_SIZE(modules); i++) { 737 printf("trying to load module %s...", modules[i]); 738 fd = drmOpen(modules[i], NULL); 739 if (fd < 0) { 740 printf("failed.\n"); 741 } else { 742 printf("success.\n"); 743 break; 744 } 745 } 746 747 if (test_vsync && !page_flipping_supported(fd)) { 748 fprintf(stderr, "page flipping not supported by drm.\n"); 749 return -1; 750 } 751 752 if (i == ARRAY_SIZE(modules)) { 753 fprintf(stderr, "failed to load any modules, aborting.\n"); 754 return -1; 755 } 756 757 resources = drmModeGetResources(fd); 758 if (!resources) { 759 fprintf(stderr, "drmModeGetResources failed: %s\n", 760 strerror(errno)); 761 drmClose(fd); 762 return 1; 763 } 764 765 dump_resource(encoders); 766 dump_resource(connectors); 767 dump_resource(crtcs); 768 dump_resource(framebuffers); 769 770 if (count > 0) { 771 set_mode(con_args, count, test_vsync); 772 getchar(); 773 } 774 775 drmModeFreeResources(resources); 776 777 return 0; 778} 779