modetest.c revision fe517fc9
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 41#ifdef HAVE_CONFIG_H 42#include "config.h" 43#endif 44 45#include <assert.h> 46#include <ctype.h> 47#include <stdbool.h> 48#include <stdio.h> 49#include <stdlib.h> 50#include <stdint.h> 51#include <inttypes.h> 52#include <unistd.h> 53#include <string.h> 54#include <strings.h> 55#include <errno.h> 56#include <poll.h> 57#include <sys/time.h> 58#ifdef HAVE_SYS_SELECT_H 59#include <sys/select.h> 60#endif 61 62#include "xf86drm.h" 63#include "xf86drmMode.h" 64#include "drm_fourcc.h" 65 66#include "util/common.h" 67#include "util/format.h" 68#include "util/kms.h" 69#include "util/pattern.h" 70 71#include "buffers.h" 72#include "cursor.h" 73 74struct crtc { 75 drmModeCrtc *crtc; 76 drmModeObjectProperties *props; 77 drmModePropertyRes **props_info; 78 drmModeModeInfo *mode; 79}; 80 81struct encoder { 82 drmModeEncoder *encoder; 83}; 84 85struct connector { 86 drmModeConnector *connector; 87 drmModeObjectProperties *props; 88 drmModePropertyRes **props_info; 89 char *name; 90}; 91 92struct fb { 93 drmModeFB *fb; 94}; 95 96struct plane { 97 drmModePlane *plane; 98 drmModeObjectProperties *props; 99 drmModePropertyRes **props_info; 100}; 101 102struct resources { 103 drmModeRes *res; 104 drmModePlaneRes *plane_res; 105 106 struct crtc *crtcs; 107 struct encoder *encoders; 108 struct connector *connectors; 109 struct fb *fbs; 110 struct plane *planes; 111}; 112 113struct device { 114 int fd; 115 116 struct resources *resources; 117 118 struct { 119 unsigned int width; 120 unsigned int height; 121 122 unsigned int fb_id; 123 struct bo *bo; 124 struct bo *cursor_bo; 125 } mode; 126}; 127 128static inline int64_t U642I64(uint64_t val) 129{ 130 return (int64_t)*((int64_t *)&val); 131} 132 133#define bit_name_fn(res) \ 134const char * res##_str(int type) { \ 135 unsigned int i; \ 136 const char *sep = ""; \ 137 for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ 138 if (type & (1 << i)) { \ 139 printf("%s%s", sep, res##_names[i]); \ 140 sep = ", "; \ 141 } \ 142 } \ 143 return NULL; \ 144} 145 146static const char *mode_type_names[] = { 147 "builtin", 148 "clock_c", 149 "crtc_c", 150 "preferred", 151 "default", 152 "userdef", 153 "driver", 154}; 155 156static bit_name_fn(mode_type) 157 158static const char *mode_flag_names[] = { 159 "phsync", 160 "nhsync", 161 "pvsync", 162 "nvsync", 163 "interlace", 164 "dblscan", 165 "csync", 166 "pcsync", 167 "ncsync", 168 "hskew", 169 "bcast", 170 "pixmux", 171 "dblclk", 172 "clkdiv2" 173}; 174 175static bit_name_fn(mode_flag) 176 177static void dump_encoders(struct device *dev) 178{ 179 drmModeEncoder *encoder; 180 int i; 181 182 printf("Encoders:\n"); 183 printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); 184 for (i = 0; i < dev->resources->res->count_encoders; i++) { 185 encoder = dev->resources->encoders[i].encoder; 186 if (!encoder) 187 continue; 188 189 printf("%d\t%d\t%s\t0x%08x\t0x%08x\n", 190 encoder->encoder_id, 191 encoder->crtc_id, 192 util_lookup_encoder_type_name(encoder->encoder_type), 193 encoder->possible_crtcs, 194 encoder->possible_clones); 195 } 196 printf("\n"); 197} 198 199static void dump_mode(drmModeModeInfo *mode) 200{ 201 printf(" %s %d %d %d %d %d %d %d %d %d", 202 mode->name, 203 mode->vrefresh, 204 mode->hdisplay, 205 mode->hsync_start, 206 mode->hsync_end, 207 mode->htotal, 208 mode->vdisplay, 209 mode->vsync_start, 210 mode->vsync_end, 211 mode->vtotal); 212 213 printf(" flags: "); 214 mode_flag_str(mode->flags); 215 printf("; type: "); 216 mode_type_str(mode->type); 217 printf("\n"); 218} 219 220static void dump_blob(struct device *dev, uint32_t blob_id) 221{ 222 uint32_t i; 223 unsigned char *blob_data; 224 drmModePropertyBlobPtr blob; 225 226 blob = drmModeGetPropertyBlob(dev->fd, blob_id); 227 if (!blob) { 228 printf("\n"); 229 return; 230 } 231 232 blob_data = blob->data; 233 234 for (i = 0; i < blob->length; i++) { 235 if (i % 16 == 0) 236 printf("\n\t\t\t"); 237 printf("%.2hhx", blob_data[i]); 238 } 239 printf("\n"); 240 241 drmModeFreePropertyBlob(blob); 242} 243 244static void dump_prop(struct device *dev, drmModePropertyPtr prop, 245 uint32_t prop_id, uint64_t value) 246{ 247 int i; 248 printf("\t%d", prop_id); 249 if (!prop) { 250 printf("\n"); 251 return; 252 } 253 254 printf(" %s:\n", prop->name); 255 256 printf("\t\tflags:"); 257 if (prop->flags & DRM_MODE_PROP_PENDING) 258 printf(" pending"); 259 if (prop->flags & DRM_MODE_PROP_IMMUTABLE) 260 printf(" immutable"); 261 if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) 262 printf(" signed range"); 263 if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) 264 printf(" range"); 265 if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) 266 printf(" enum"); 267 if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) 268 printf(" bitmask"); 269 if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) 270 printf(" blob"); 271 if (drm_property_type_is(prop, DRM_MODE_PROP_OBJECT)) 272 printf(" object"); 273 printf("\n"); 274 275 if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) { 276 printf("\t\tvalues:"); 277 for (i = 0; i < prop->count_values; i++) 278 printf(" %"PRId64, U642I64(prop->values[i])); 279 printf("\n"); 280 } 281 282 if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) { 283 printf("\t\tvalues:"); 284 for (i = 0; i < prop->count_values; i++) 285 printf(" %"PRIu64, prop->values[i]); 286 printf("\n"); 287 } 288 289 if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) { 290 printf("\t\tenums:"); 291 for (i = 0; i < prop->count_enums; i++) 292 printf(" %s=%llu", prop->enums[i].name, 293 prop->enums[i].value); 294 printf("\n"); 295 } else if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) { 296 printf("\t\tvalues:"); 297 for (i = 0; i < prop->count_enums; i++) 298 printf(" %s=0x%llx", prop->enums[i].name, 299 (1LL << prop->enums[i].value)); 300 printf("\n"); 301 } else { 302 assert(prop->count_enums == 0); 303 } 304 305 if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) { 306 printf("\t\tblobs:\n"); 307 for (i = 0; i < prop->count_blobs; i++) 308 dump_blob(dev, prop->blob_ids[i]); 309 printf("\n"); 310 } else { 311 assert(prop->count_blobs == 0); 312 } 313 314 printf("\t\tvalue:"); 315 if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) 316 dump_blob(dev, value); 317 else if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) 318 printf(" %"PRId64"\n", value); 319 else 320 printf(" %"PRIu64"\n", value); 321} 322 323static void dump_connectors(struct device *dev) 324{ 325 int i, j; 326 327 printf("Connectors:\n"); 328 printf("id\tencoder\tstatus\t\tname\t\tsize (mm)\tmodes\tencoders\n"); 329 for (i = 0; i < dev->resources->res->count_connectors; i++) { 330 struct connector *_connector = &dev->resources->connectors[i]; 331 drmModeConnector *connector = _connector->connector; 332 if (!connector) 333 continue; 334 335 printf("%d\t%d\t%s\t%-15s\t%dx%d\t\t%d\t", 336 connector->connector_id, 337 connector->encoder_id, 338 util_lookup_connector_status_name(connector->connection), 339 _connector->name, 340 connector->mmWidth, connector->mmHeight, 341 connector->count_modes); 342 343 for (j = 0; j < connector->count_encoders; j++) 344 printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]); 345 printf("\n"); 346 347 if (connector->count_modes) { 348 printf(" modes:\n"); 349 printf("\tname refresh (Hz) hdisp hss hse htot vdisp " 350 "vss vse vtot)\n"); 351 for (j = 0; j < connector->count_modes; j++) 352 dump_mode(&connector->modes[j]); 353 } 354 355 if (_connector->props) { 356 printf(" props:\n"); 357 for (j = 0; j < (int)_connector->props->count_props; j++) 358 dump_prop(dev, _connector->props_info[j], 359 _connector->props->props[j], 360 _connector->props->prop_values[j]); 361 } 362 } 363 printf("\n"); 364} 365 366static void dump_crtcs(struct device *dev) 367{ 368 int i; 369 uint32_t j; 370 371 printf("CRTCs:\n"); 372 printf("id\tfb\tpos\tsize\n"); 373 for (i = 0; i < dev->resources->res->count_crtcs; i++) { 374 struct crtc *_crtc = &dev->resources->crtcs[i]; 375 drmModeCrtc *crtc = _crtc->crtc; 376 if (!crtc) 377 continue; 378 379 printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", 380 crtc->crtc_id, 381 crtc->buffer_id, 382 crtc->x, crtc->y, 383 crtc->width, crtc->height); 384 dump_mode(&crtc->mode); 385 386 if (_crtc->props) { 387 printf(" props:\n"); 388 for (j = 0; j < _crtc->props->count_props; j++) 389 dump_prop(dev, _crtc->props_info[j], 390 _crtc->props->props[j], 391 _crtc->props->prop_values[j]); 392 } else { 393 printf(" no properties found\n"); 394 } 395 } 396 printf("\n"); 397} 398 399static void dump_framebuffers(struct device *dev) 400{ 401 drmModeFB *fb; 402 int i; 403 404 printf("Frame buffers:\n"); 405 printf("id\tsize\tpitch\n"); 406 for (i = 0; i < dev->resources->res->count_fbs; i++) { 407 fb = dev->resources->fbs[i].fb; 408 if (!fb) 409 continue; 410 411 printf("%u\t(%ux%u)\t%u\n", 412 fb->fb_id, 413 fb->width, fb->height, 414 fb->pitch); 415 } 416 printf("\n"); 417} 418 419static void dump_planes(struct device *dev) 420{ 421 unsigned int i, j; 422 423 printf("Planes:\n"); 424 printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n"); 425 426 if (!dev->resources->plane_res) 427 return; 428 429 for (i = 0; i < dev->resources->plane_res->count_planes; i++) { 430 struct plane *plane = &dev->resources->planes[i]; 431 drmModePlane *ovr = plane->plane; 432 if (!ovr) 433 continue; 434 435 printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%-8d\t0x%08x\n", 436 ovr->plane_id, ovr->crtc_id, ovr->fb_id, 437 ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y, 438 ovr->gamma_size, ovr->possible_crtcs); 439 440 if (!ovr->count_formats) 441 continue; 442 443 printf(" formats:"); 444 for (j = 0; j < ovr->count_formats; j++) 445 printf(" %4.4s", (char *)&ovr->formats[j]); 446 printf("\n"); 447 448 if (plane->props) { 449 printf(" props:\n"); 450 for (j = 0; j < plane->props->count_props; j++) 451 dump_prop(dev, plane->props_info[j], 452 plane->props->props[j], 453 plane->props->prop_values[j]); 454 } else { 455 printf(" no properties found\n"); 456 } 457 } 458 printf("\n"); 459 460 return; 461} 462 463static void free_resources(struct resources *res) 464{ 465 int i; 466 467 if (!res) 468 return; 469 470#define free_resource(_res, __res, type, Type) \ 471 do { \ 472 if (!(_res)->type##s) \ 473 break; \ 474 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ 475 if (!(_res)->type##s[i].type) \ 476 break; \ 477 drmModeFree##Type((_res)->type##s[i].type); \ 478 } \ 479 free((_res)->type##s); \ 480 } while (0) 481 482#define free_properties(_res, __res, type) \ 483 do { \ 484 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ 485 drmModeFreeObjectProperties(res->type##s[i].props); \ 486 free(res->type##s[i].props_info); \ 487 } \ 488 } while (0) 489 490 if (res->res) { 491 free_properties(res, res, crtc); 492 493 free_resource(res, res, crtc, Crtc); 494 free_resource(res, res, encoder, Encoder); 495 496 for (i = 0; i < res->res->count_connectors; i++) 497 free(res->connectors[i].name); 498 499 free_resource(res, res, connector, Connector); 500 free_resource(res, res, fb, FB); 501 502 drmModeFreeResources(res->res); 503 } 504 505 if (res->plane_res) { 506 free_properties(res, plane_res, plane); 507 508 free_resource(res, plane_res, plane, Plane); 509 510 drmModeFreePlaneResources(res->plane_res); 511 } 512 513 free(res); 514} 515 516static struct resources *get_resources(struct device *dev) 517{ 518 struct resources *res; 519 int i; 520 521 res = calloc(1, sizeof(*res)); 522 if (res == 0) 523 return NULL; 524 525 drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); 526 527 drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); 528 529 res->res = drmModeGetResources(dev->fd); 530 if (!res->res) { 531 fprintf(stderr, "drmModeGetResources failed: %s\n", 532 strerror(errno)); 533 goto error; 534 } 535 536 res->crtcs = calloc(res->res->count_crtcs, sizeof(*res->crtcs)); 537 res->encoders = calloc(res->res->count_encoders, sizeof(*res->encoders)); 538 res->connectors = calloc(res->res->count_connectors, sizeof(*res->connectors)); 539 res->fbs = calloc(res->res->count_fbs, sizeof(*res->fbs)); 540 541 if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs) 542 goto error; 543 544#define get_resource(_res, __res, type, Type) \ 545 do { \ 546 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ 547 (_res)->type##s[i].type = \ 548 drmModeGet##Type(dev->fd, (_res)->__res->type##s[i]); \ 549 if (!(_res)->type##s[i].type) \ 550 fprintf(stderr, "could not get %s %i: %s\n", \ 551 #type, (_res)->__res->type##s[i], \ 552 strerror(errno)); \ 553 } \ 554 } while (0) 555 556 get_resource(res, res, crtc, Crtc); 557 get_resource(res, res, encoder, Encoder); 558 get_resource(res, res, connector, Connector); 559 get_resource(res, res, fb, FB); 560 561 /* Set the name of all connectors based on the type name and the per-type ID. */ 562 for (i = 0; i < res->res->count_connectors; i++) { 563 struct connector *connector = &res->connectors[i]; 564 drmModeConnector *conn = connector->connector; 565 566 asprintf(&connector->name, "%s-%u", 567 util_lookup_connector_type_name(conn->connector_type), 568 conn->connector_type_id); 569 } 570 571#define get_properties(_res, __res, type, Type) \ 572 do { \ 573 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ 574 struct type *obj = &res->type##s[i]; \ 575 unsigned int j; \ 576 obj->props = \ 577 drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \ 578 DRM_MODE_OBJECT_##Type); \ 579 if (!obj->props) { \ 580 fprintf(stderr, \ 581 "could not get %s %i properties: %s\n", \ 582 #type, obj->type->type##_id, \ 583 strerror(errno)); \ 584 continue; \ 585 } \ 586 obj->props_info = calloc(obj->props->count_props, \ 587 sizeof(*obj->props_info)); \ 588 if (!obj->props_info) \ 589 continue; \ 590 for (j = 0; j < obj->props->count_props; ++j) \ 591 obj->props_info[j] = \ 592 drmModeGetProperty(dev->fd, obj->props->props[j]); \ 593 } \ 594 } while (0) 595 596 get_properties(res, res, crtc, CRTC); 597 get_properties(res, res, connector, CONNECTOR); 598 599 for (i = 0; i < res->res->count_crtcs; ++i) 600 res->crtcs[i].mode = &res->crtcs[i].crtc->mode; 601 602 res->plane_res = drmModeGetPlaneResources(dev->fd); 603 if (!res->plane_res) { 604 fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", 605 strerror(errno)); 606 return res; 607 } 608 609 res->planes = calloc(res->plane_res->count_planes, sizeof(*res->planes)); 610 if (!res->planes) 611 goto error; 612 613 get_resource(res, plane_res, plane, Plane); 614 get_properties(res, plane_res, plane, PLANE); 615 616 return res; 617 618error: 619 free_resources(res); 620 return NULL; 621} 622 623static int get_crtc_index(struct device *dev, uint32_t id) 624{ 625 int i; 626 627 for (i = 0; i < dev->resources->res->count_crtcs; ++i) { 628 drmModeCrtc *crtc = dev->resources->crtcs[i].crtc; 629 if (crtc && crtc->crtc_id == id) 630 return i; 631 } 632 633 return -1; 634} 635 636static drmModeConnector *get_connector_by_name(struct device *dev, const char *name) 637{ 638 struct connector *connector; 639 int i; 640 641 for (i = 0; i < dev->resources->res->count_connectors; i++) { 642 connector = &dev->resources->connectors[i]; 643 644 if (strcmp(connector->name, name) == 0) 645 return connector->connector; 646 } 647 648 return NULL; 649} 650 651static drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id) 652{ 653 drmModeConnector *connector; 654 int i; 655 656 for (i = 0; i < dev->resources->res->count_connectors; i++) { 657 connector = dev->resources->connectors[i].connector; 658 if (connector && connector->connector_id == id) 659 return connector; 660 } 661 662 return NULL; 663} 664 665static drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id) 666{ 667 drmModeEncoder *encoder; 668 int i; 669 670 for (i = 0; i < dev->resources->res->count_encoders; i++) { 671 encoder = dev->resources->encoders[i].encoder; 672 if (encoder && encoder->encoder_id == id) 673 return encoder; 674 } 675 676 return NULL; 677} 678 679/* ----------------------------------------------------------------------------- 680 * Pipes and planes 681 */ 682 683/* 684 * Mode setting with the kernel interfaces is a bit of a chore. 685 * First you have to find the connector in question and make sure the 686 * requested mode is available. 687 * Then you need to find the encoder attached to that connector so you 688 * can bind it with a free crtc. 689 */ 690struct pipe_arg { 691 const char **cons; 692 uint32_t *con_ids; 693 unsigned int num_cons; 694 uint32_t crtc_id; 695 char mode_str[64]; 696 char format_str[5]; 697 unsigned int vrefresh; 698 unsigned int fourcc; 699 drmModeModeInfo *mode; 700 struct crtc *crtc; 701 unsigned int fb_id[2], current_fb_id; 702 struct timeval start; 703 704 int swap_count; 705}; 706 707struct plane_arg { 708 uint32_t crtc_id; /* the id of CRTC to bind to */ 709 bool has_position; 710 int32_t x, y; 711 uint32_t w, h; 712 double scale; 713 unsigned int fb_id; 714 struct bo *bo; 715 char format_str[5]; /* need to leave room for terminating \0 */ 716 unsigned int fourcc; 717}; 718 719static drmModeModeInfo * 720connector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str, 721 const unsigned int vrefresh) 722{ 723 drmModeConnector *connector; 724 drmModeModeInfo *mode; 725 int i; 726 727 connector = get_connector_by_id(dev, con_id); 728 if (!connector || !connector->count_modes) 729 return NULL; 730 731 for (i = 0; i < connector->count_modes; i++) { 732 mode = &connector->modes[i]; 733 if (!strcmp(mode->name, mode_str)) { 734 /* If the vertical refresh frequency is not specified then return the 735 * first mode that match with the name. Else, return the mode that match 736 * the name and the specified vertical refresh frequency. 737 */ 738 if (vrefresh == 0) 739 return mode; 740 else if (mode->vrefresh == vrefresh) 741 return mode; 742 } 743 } 744 745 return NULL; 746} 747 748static struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe) 749{ 750 uint32_t possible_crtcs = ~0; 751 uint32_t active_crtcs = 0; 752 unsigned int crtc_idx; 753 unsigned int i; 754 int j; 755 756 for (i = 0; i < pipe->num_cons; ++i) { 757 uint32_t crtcs_for_connector = 0; 758 drmModeConnector *connector; 759 drmModeEncoder *encoder; 760 int idx; 761 762 connector = get_connector_by_id(dev, pipe->con_ids[i]); 763 if (!connector) 764 return NULL; 765 766 for (j = 0; j < connector->count_encoders; ++j) { 767 encoder = get_encoder_by_id(dev, connector->encoders[j]); 768 if (!encoder) 769 continue; 770 771 crtcs_for_connector |= encoder->possible_crtcs; 772 773 idx = get_crtc_index(dev, encoder->crtc_id); 774 if (idx >= 0) 775 active_crtcs |= 1 << idx; 776 } 777 778 possible_crtcs &= crtcs_for_connector; 779 } 780 781 if (!possible_crtcs) 782 return NULL; 783 784 /* Return the first possible and active CRTC if one exists, or the first 785 * possible CRTC otherwise. 786 */ 787 if (possible_crtcs & active_crtcs) 788 crtc_idx = ffs(possible_crtcs & active_crtcs); 789 else 790 crtc_idx = ffs(possible_crtcs); 791 792 return &dev->resources->crtcs[crtc_idx - 1]; 793} 794 795static int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe) 796{ 797 drmModeModeInfo *mode = NULL; 798 int i; 799 800 pipe->mode = NULL; 801 802 for (i = 0; i < (int)pipe->num_cons; i++) { 803 mode = connector_find_mode(dev, pipe->con_ids[i], 804 pipe->mode_str, pipe->vrefresh); 805 if (mode == NULL) { 806 fprintf(stderr, 807 "failed to find mode \"%s\" for connector %s\n", 808 pipe->mode_str, pipe->cons[i]); 809 return -EINVAL; 810 } 811 } 812 813 /* If the CRTC ID was specified, get the corresponding CRTC. Otherwise 814 * locate a CRTC that can be attached to all the connectors. 815 */ 816 if (pipe->crtc_id != (uint32_t)-1) { 817 for (i = 0; i < dev->resources->res->count_crtcs; i++) { 818 struct crtc *crtc = &dev->resources->crtcs[i]; 819 820 if (pipe->crtc_id == crtc->crtc->crtc_id) { 821 pipe->crtc = crtc; 822 break; 823 } 824 } 825 } else { 826 pipe->crtc = pipe_find_crtc(dev, pipe); 827 } 828 829 if (!pipe->crtc) { 830 fprintf(stderr, "failed to find CRTC for pipe\n"); 831 return -EINVAL; 832 } 833 834 pipe->mode = mode; 835 pipe->crtc->mode = mode; 836 837 return 0; 838} 839 840/* ----------------------------------------------------------------------------- 841 * Properties 842 */ 843 844struct property_arg { 845 uint32_t obj_id; 846 uint32_t obj_type; 847 char name[DRM_PROP_NAME_LEN+1]; 848 uint32_t prop_id; 849 uint64_t value; 850}; 851 852static void set_property(struct device *dev, struct property_arg *p) 853{ 854 drmModeObjectProperties *props = NULL; 855 drmModePropertyRes **props_info = NULL; 856 const char *obj_type; 857 int ret; 858 int i; 859 860 p->obj_type = 0; 861 p->prop_id = 0; 862 863#define find_object(_res, __res, type, Type) \ 864 do { \ 865 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ 866 struct type *obj = &(_res)->type##s[i]; \ 867 if (obj->type->type##_id != p->obj_id) \ 868 continue; \ 869 p->obj_type = DRM_MODE_OBJECT_##Type; \ 870 obj_type = #Type; \ 871 props = obj->props; \ 872 props_info = obj->props_info; \ 873 } \ 874 } while(0) \ 875 876 find_object(dev->resources, res, crtc, CRTC); 877 if (p->obj_type == 0) 878 find_object(dev->resources, res, connector, CONNECTOR); 879 if (p->obj_type == 0) 880 find_object(dev->resources, plane_res, plane, PLANE); 881 if (p->obj_type == 0) { 882 fprintf(stderr, "Object %i not found, can't set property\n", 883 p->obj_id); 884 return; 885 } 886 887 if (!props) { 888 fprintf(stderr, "%s %i has no properties\n", 889 obj_type, p->obj_id); 890 return; 891 } 892 893 for (i = 0; i < (int)props->count_props; ++i) { 894 if (!props_info[i]) 895 continue; 896 if (strcmp(props_info[i]->name, p->name) == 0) 897 break; 898 } 899 900 if (i == (int)props->count_props) { 901 fprintf(stderr, "%s %i has no %s property\n", 902 obj_type, p->obj_id, p->name); 903 return; 904 } 905 906 p->prop_id = props->props[i]; 907 908 ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type, 909 p->prop_id, p->value); 910 if (ret < 0) 911 fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n", 912 obj_type, p->obj_id, p->name, p->value, strerror(errno)); 913} 914 915/* -------------------------------------------------------------------------- */ 916 917static void 918page_flip_handler(int fd, unsigned int frame, 919 unsigned int sec, unsigned int usec, void *data) 920{ 921 struct pipe_arg *pipe; 922 unsigned int new_fb_id; 923 struct timeval end; 924 double t; 925 926 pipe = data; 927 if (pipe->current_fb_id == pipe->fb_id[0]) 928 new_fb_id = pipe->fb_id[1]; 929 else 930 new_fb_id = pipe->fb_id[0]; 931 932 drmModePageFlip(fd, pipe->crtc->crtc->crtc_id, new_fb_id, 933 DRM_MODE_PAGE_FLIP_EVENT, pipe); 934 pipe->current_fb_id = new_fb_id; 935 pipe->swap_count++; 936 if (pipe->swap_count == 60) { 937 gettimeofday(&end, NULL); 938 t = end.tv_sec + end.tv_usec * 1e-6 - 939 (pipe->start.tv_sec + pipe->start.tv_usec * 1e-6); 940 fprintf(stderr, "freq: %.02fHz\n", pipe->swap_count / t); 941 pipe->swap_count = 0; 942 pipe->start = end; 943 } 944} 945 946static bool format_support(const drmModePlanePtr ovr, uint32_t fmt) 947{ 948 unsigned int i; 949 950 for (i = 0; i < ovr->count_formats; ++i) { 951 if (ovr->formats[i] == fmt) 952 return true; 953 } 954 955 return false; 956} 957 958static int set_plane(struct device *dev, struct plane_arg *p) 959{ 960 drmModePlane *ovr; 961 uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; 962 uint32_t plane_id = 0; 963 struct bo *plane_bo; 964 uint32_t plane_flags = 0; 965 int crtc_x, crtc_y, crtc_w, crtc_h; 966 struct crtc *crtc = NULL; 967 unsigned int pipe; 968 unsigned int i; 969 970 /* Find an unused plane which can be connected to our CRTC. Find the 971 * CRTC index first, then iterate over available planes. 972 */ 973 for (i = 0; i < (unsigned int)dev->resources->res->count_crtcs; i++) { 974 if (p->crtc_id == dev->resources->res->crtcs[i]) { 975 crtc = &dev->resources->crtcs[i]; 976 pipe = i; 977 break; 978 } 979 } 980 981 if (!crtc) { 982 fprintf(stderr, "CRTC %u not found\n", p->crtc_id); 983 return -1; 984 } 985 986 for (i = 0; i < dev->resources->plane_res->count_planes && !plane_id; i++) { 987 ovr = dev->resources->planes[i].plane; 988 if (!ovr || !format_support(ovr, p->fourcc)) 989 continue; 990 991 if ((ovr->possible_crtcs & (1 << pipe)) && !ovr->crtc_id) 992 plane_id = ovr->plane_id; 993 } 994 995 if (!plane_id) { 996 fprintf(stderr, "no unused plane available for CRTC %u\n", 997 crtc->crtc->crtc_id); 998 return -1; 999 } 1000 1001 fprintf(stderr, "testing %dx%d@%s overlay plane %u\n", 1002 p->w, p->h, p->format_str, plane_id); 1003 1004 plane_bo = bo_create(dev->fd, p->fourcc, p->w, p->h, handles, 1005 pitches, offsets, UTIL_PATTERN_TILES); 1006 if (plane_bo == NULL) 1007 return -1; 1008 1009 p->bo = plane_bo; 1010 1011 /* just use single plane format for now.. */ 1012 if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc, 1013 handles, pitches, offsets, &p->fb_id, plane_flags)) { 1014 fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 1015 return -1; 1016 } 1017 1018 crtc_w = p->w * p->scale; 1019 crtc_h = p->h * p->scale; 1020 if (!p->has_position) { 1021 /* Default to the middle of the screen */ 1022 crtc_x = (crtc->mode->hdisplay - crtc_w) / 2; 1023 crtc_y = (crtc->mode->vdisplay - crtc_h) / 2; 1024 } else { 1025 crtc_x = p->x; 1026 crtc_y = p->y; 1027 } 1028 1029 /* note src coords (last 4 args) are in Q16 format */ 1030 if (drmModeSetPlane(dev->fd, plane_id, crtc->crtc->crtc_id, p->fb_id, 1031 plane_flags, crtc_x, crtc_y, crtc_w, crtc_h, 1032 0, 0, p->w << 16, p->h << 16)) { 1033 fprintf(stderr, "failed to enable plane: %s\n", 1034 strerror(errno)); 1035 return -1; 1036 } 1037 1038 ovr->crtc_id = crtc->crtc->crtc_id; 1039 1040 return 0; 1041} 1042 1043static void clear_planes(struct device *dev, struct plane_arg *p, unsigned int count) 1044{ 1045 unsigned int i; 1046 1047 for (i = 0; i < count; i++) { 1048 if (p[i].fb_id) 1049 drmModeRmFB(dev->fd, p[i].fb_id); 1050 if (p[i].bo) 1051 bo_destroy(p[i].bo); 1052 } 1053} 1054 1055 1056static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) 1057{ 1058 uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; 1059 unsigned int fb_id; 1060 struct bo *bo; 1061 unsigned int i; 1062 unsigned int j; 1063 int ret, x; 1064 1065 dev->mode.width = 0; 1066 dev->mode.height = 0; 1067 dev->mode.fb_id = 0; 1068 1069 for (i = 0; i < count; i++) { 1070 struct pipe_arg *pipe = &pipes[i]; 1071 1072 ret = pipe_find_crtc_and_mode(dev, pipe); 1073 if (ret < 0) 1074 continue; 1075 1076 dev->mode.width += pipe->mode->hdisplay; 1077 if (dev->mode.height < pipe->mode->vdisplay) 1078 dev->mode.height = pipe->mode->vdisplay; 1079 } 1080 1081 bo = bo_create(dev->fd, pipes[0].fourcc, dev->mode.width, 1082 dev->mode.height, handles, pitches, offsets, 1083 UTIL_PATTERN_SMPTE); 1084 if (bo == NULL) 1085 return; 1086 1087 dev->mode.bo = bo; 1088 1089 ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height, 1090 pipes[0].fourcc, handles, pitches, offsets, &fb_id, 0); 1091 if (ret) { 1092 fprintf(stderr, "failed to add fb (%ux%u): %s\n", 1093 dev->mode.width, dev->mode.height, strerror(errno)); 1094 return; 1095 } 1096 1097 dev->mode.fb_id = fb_id; 1098 1099 x = 0; 1100 for (i = 0; i < count; i++) { 1101 struct pipe_arg *pipe = &pipes[i]; 1102 1103 if (pipe->mode == NULL) 1104 continue; 1105 1106 printf("setting mode %s-%dHz@%s on connectors ", 1107 pipe->mode_str, pipe->mode->vrefresh, pipe->format_str); 1108 for (j = 0; j < pipe->num_cons; ++j) 1109 printf("%s, ", pipe->cons[j]); 1110 printf("crtc %d\n", pipe->crtc->crtc->crtc_id); 1111 1112 ret = drmModeSetCrtc(dev->fd, pipe->crtc->crtc->crtc_id, fb_id, 1113 x, 0, pipe->con_ids, pipe->num_cons, 1114 pipe->mode); 1115 1116 /* XXX: Actually check if this is needed */ 1117 drmModeDirtyFB(dev->fd, fb_id, NULL, 0); 1118 1119 x += pipe->mode->hdisplay; 1120 1121 if (ret) { 1122 fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); 1123 return; 1124 } 1125 } 1126} 1127 1128static void clear_mode(struct device *dev) 1129{ 1130 if (dev->mode.fb_id) 1131 drmModeRmFB(dev->fd, dev->mode.fb_id); 1132 if (dev->mode.bo) 1133 bo_destroy(dev->mode.bo); 1134} 1135 1136static void set_planes(struct device *dev, struct plane_arg *p, unsigned int count) 1137{ 1138 unsigned int i; 1139 1140 /* set up planes/overlays */ 1141 for (i = 0; i < count; i++) 1142 if (set_plane(dev, &p[i])) 1143 return; 1144} 1145 1146static void set_cursors(struct device *dev, struct pipe_arg *pipes, unsigned int count) 1147{ 1148 uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; 1149 struct bo *bo; 1150 unsigned int i; 1151 int ret; 1152 1153 /* maybe make cursor width/height configurable some day */ 1154 uint32_t cw = 64; 1155 uint32_t ch = 64; 1156 1157 /* create cursor bo.. just using PATTERN_PLAIN as it has 1158 * translucent alpha 1159 */ 1160 bo = bo_create(dev->fd, DRM_FORMAT_ARGB8888, cw, ch, handles, pitches, 1161 offsets, UTIL_PATTERN_PLAIN); 1162 if (bo == NULL) 1163 return; 1164 1165 dev->mode.cursor_bo = bo; 1166 1167 for (i = 0; i < count; i++) { 1168 struct pipe_arg *pipe = &pipes[i]; 1169 ret = cursor_init(dev->fd, handles[0], 1170 pipe->crtc->crtc->crtc_id, 1171 pipe->mode->hdisplay, pipe->mode->vdisplay, 1172 cw, ch); 1173 if (ret) { 1174 fprintf(stderr, "failed to init cursor for CRTC[%u]\n", 1175 pipe->crtc_id); 1176 return; 1177 } 1178 } 1179 1180 cursor_start(); 1181} 1182 1183static void clear_cursors(struct device *dev) 1184{ 1185 cursor_stop(); 1186 1187 if (dev->mode.cursor_bo) 1188 bo_destroy(dev->mode.cursor_bo); 1189} 1190 1191static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned int count) 1192{ 1193 uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; 1194 unsigned int other_fb_id; 1195 struct bo *other_bo; 1196 drmEventContext evctx; 1197 unsigned int i; 1198 int ret; 1199 1200 other_bo = bo_create(dev->fd, pipes[0].fourcc, dev->mode.width, 1201 dev->mode.height, handles, pitches, offsets, 1202 UTIL_PATTERN_PLAIN); 1203 if (other_bo == NULL) 1204 return; 1205 1206 ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height, 1207 pipes[0].fourcc, handles, pitches, offsets, 1208 &other_fb_id, 0); 1209 if (ret) { 1210 fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 1211 goto err; 1212 } 1213 1214 for (i = 0; i < count; i++) { 1215 struct pipe_arg *pipe = &pipes[i]; 1216 1217 if (pipe->mode == NULL) 1218 continue; 1219 1220 ret = drmModePageFlip(dev->fd, pipe->crtc->crtc->crtc_id, 1221 other_fb_id, DRM_MODE_PAGE_FLIP_EVENT, 1222 pipe); 1223 if (ret) { 1224 fprintf(stderr, "failed to page flip: %s\n", strerror(errno)); 1225 goto err_rmfb; 1226 } 1227 gettimeofday(&pipe->start, NULL); 1228 pipe->swap_count = 0; 1229 pipe->fb_id[0] = dev->mode.fb_id; 1230 pipe->fb_id[1] = other_fb_id; 1231 pipe->current_fb_id = other_fb_id; 1232 } 1233 1234 memset(&evctx, 0, sizeof evctx); 1235 evctx.version = DRM_EVENT_CONTEXT_VERSION; 1236 evctx.vblank_handler = NULL; 1237 evctx.page_flip_handler = page_flip_handler; 1238 1239 while (1) { 1240#if 0 1241 struct pollfd pfd[2]; 1242 1243 pfd[0].fd = 0; 1244 pfd[0].events = POLLIN; 1245 pfd[1].fd = fd; 1246 pfd[1].events = POLLIN; 1247 1248 if (poll(pfd, 2, -1) < 0) { 1249 fprintf(stderr, "poll error\n"); 1250 break; 1251 } 1252 1253 if (pfd[0].revents) 1254 break; 1255#else 1256 struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; 1257 fd_set fds; 1258 1259 FD_ZERO(&fds); 1260 FD_SET(0, &fds); 1261 FD_SET(dev->fd, &fds); 1262 ret = select(dev->fd + 1, &fds, NULL, NULL, &timeout); 1263 1264 if (ret <= 0) { 1265 fprintf(stderr, "select timed out or error (ret %d)\n", 1266 ret); 1267 continue; 1268 } else if (FD_ISSET(0, &fds)) { 1269 break; 1270 } 1271#endif 1272 1273 drmHandleEvent(dev->fd, &evctx); 1274 } 1275 1276err_rmfb: 1277 drmModeRmFB(dev->fd, other_fb_id); 1278err: 1279 bo_destroy(other_bo); 1280} 1281 1282#define min(a, b) ((a) < (b) ? (a) : (b)) 1283 1284static int parse_connector(struct pipe_arg *pipe, const char *arg) 1285{ 1286 unsigned int len; 1287 unsigned int i; 1288 const char *p; 1289 char *endp; 1290 1291 pipe->vrefresh = 0; 1292 pipe->crtc_id = (uint32_t)-1; 1293 strcpy(pipe->format_str, "XR24"); 1294 1295 /* Count the number of connectors and allocate them. */ 1296 pipe->num_cons = 1; 1297 for (p = arg; *p && *p != ':' && *p != '@'; ++p) { 1298 if (*p == ',') 1299 pipe->num_cons++; 1300 } 1301 1302 pipe->con_ids = calloc(pipe->num_cons, sizeof(*pipe->con_ids)); 1303 pipe->cons = calloc(pipe->num_cons, sizeof(*pipe->cons)); 1304 if (pipe->con_ids == NULL || pipe->cons == NULL) 1305 return -1; 1306 1307 /* Parse the connectors. */ 1308 for (i = 0, p = arg; i < pipe->num_cons; ++i, p = endp + 1) { 1309 endp = strpbrk(p, ",@:"); 1310 if (!endp) 1311 break; 1312 1313 pipe->cons[i] = strndup(p, endp - p); 1314 1315 if (*endp != ',') 1316 break; 1317 } 1318 1319 if (i != pipe->num_cons - 1) 1320 return -1; 1321 1322 /* Parse the remaining parameters. */ 1323 if (*endp == '@') { 1324 arg = endp + 1; 1325 pipe->crtc_id = strtoul(arg, &endp, 10); 1326 } 1327 if (*endp != ':') 1328 return -1; 1329 1330 arg = endp + 1; 1331 1332 /* Search for the vertical refresh or the format. */ 1333 p = strpbrk(arg, "-@"); 1334 if (p == NULL) 1335 p = arg + strlen(arg); 1336 len = min(sizeof pipe->mode_str - 1, (unsigned int)(p - arg)); 1337 strncpy(pipe->mode_str, arg, len); 1338 pipe->mode_str[len] = '\0'; 1339 1340 if (*p == '-') { 1341 pipe->vrefresh = strtoul(p + 1, &endp, 10); 1342 p = endp; 1343 } 1344 1345 if (*p == '@') { 1346 strncpy(pipe->format_str, p + 1, 4); 1347 pipe->format_str[4] = '\0'; 1348 } 1349 1350 pipe->fourcc = util_format_fourcc(pipe->format_str); 1351 if (pipe->fourcc == 0) { 1352 fprintf(stderr, "unknown format %s\n", pipe->format_str); 1353 return -1; 1354 } 1355 1356 return 0; 1357} 1358 1359static int parse_plane(struct plane_arg *plane, const char *p) 1360{ 1361 char *end; 1362 1363 plane->crtc_id = strtoul(p, &end, 10); 1364 if (*end != ':') 1365 return -EINVAL; 1366 1367 p = end + 1; 1368 plane->w = strtoul(p, &end, 10); 1369 if (*end != 'x') 1370 return -EINVAL; 1371 1372 p = end + 1; 1373 plane->h = strtoul(p, &end, 10); 1374 1375 if (*end == '+' || *end == '-') { 1376 plane->x = strtol(end, &end, 10); 1377 if (*end != '+' && *end != '-') 1378 return -EINVAL; 1379 plane->y = strtol(end, &end, 10); 1380 1381 plane->has_position = true; 1382 } 1383 1384 if (*end == '*') { 1385 p = end + 1; 1386 plane->scale = strtod(p, &end); 1387 if (plane->scale <= 0.0) 1388 return -EINVAL; 1389 } else { 1390 plane->scale = 1.0; 1391 } 1392 1393 if (*end == '@') { 1394 p = end + 1; 1395 if (strlen(p) != 4) 1396 return -EINVAL; 1397 1398 strcpy(plane->format_str, p); 1399 } else { 1400 strcpy(plane->format_str, "XR24"); 1401 } 1402 1403 plane->fourcc = util_format_fourcc(plane->format_str); 1404 if (plane->fourcc == 0) { 1405 fprintf(stderr, "unknown format %s\n", plane->format_str); 1406 return -EINVAL; 1407 } 1408 1409 return 0; 1410} 1411 1412static int parse_property(struct property_arg *p, const char *arg) 1413{ 1414 if (sscanf(arg, "%d:%32[^:]:%" SCNu64, &p->obj_id, p->name, &p->value) != 3) 1415 return -1; 1416 1417 p->obj_type = 0; 1418 p->name[DRM_PROP_NAME_LEN] = '\0'; 1419 1420 return 0; 1421} 1422 1423static void usage(char *name) 1424{ 1425 fprintf(stderr, "usage: %s [-cDdefMPpsCvw]\n", name); 1426 1427 fprintf(stderr, "\n Query options:\n\n"); 1428 fprintf(stderr, "\t-c\tlist connectors\n"); 1429 fprintf(stderr, "\t-e\tlist encoders\n"); 1430 fprintf(stderr, "\t-f\tlist framebuffers\n"); 1431 fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n"); 1432 1433 fprintf(stderr, "\n Test options:\n\n"); 1434 fprintf(stderr, "\t-P <crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n"); 1435 fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[-<vrefresh>][@<format>]\tset a mode\n"); 1436 fprintf(stderr, "\t-C\ttest hw cursor\n"); 1437 fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); 1438 fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n"); 1439 1440 fprintf(stderr, "\n Generic options:\n\n"); 1441 fprintf(stderr, "\t-d\tdrop master after mode set\n"); 1442 fprintf(stderr, "\t-M module\tuse the given driver\n"); 1443 fprintf(stderr, "\t-D device\tuse the given device\n"); 1444 1445 fprintf(stderr, "\n\tDefault is to dump all info.\n"); 1446 exit(0); 1447} 1448 1449static int page_flipping_supported(void) 1450{ 1451 /*FIXME: generic ioctl needed? */ 1452 return 1; 1453#if 0 1454 int ret, value; 1455 struct drm_i915_getparam gp; 1456 1457 gp.param = I915_PARAM_HAS_PAGEFLIPPING; 1458 gp.value = &value; 1459 1460 ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp)); 1461 if (ret) { 1462 fprintf(stderr, "drm_i915_getparam: %m\n"); 1463 return 0; 1464 } 1465 1466 return *gp.value; 1467#endif 1468} 1469 1470static int cursor_supported(void) 1471{ 1472 /*FIXME: generic ioctl needed? */ 1473 return 1; 1474} 1475 1476static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe) 1477{ 1478 drmModeConnector *connector; 1479 unsigned int i; 1480 uint32_t id; 1481 char *endp; 1482 1483 for (i = 0; i < pipe->num_cons; i++) { 1484 id = strtoul(pipe->cons[i], &endp, 10); 1485 if (endp == pipe->cons[i]) { 1486 connector = get_connector_by_name(dev, pipe->cons[i]); 1487 if (!connector) { 1488 fprintf(stderr, "no connector named '%s'\n", 1489 pipe->cons[i]); 1490 return -ENODEV; 1491 } 1492 1493 id = connector->connector_id; 1494 } 1495 1496 pipe->con_ids[i] = id; 1497 } 1498 1499 return 0; 1500} 1501 1502static char optstr[] = "cdD:efM:P:ps:Cvw:"; 1503 1504int main(int argc, char **argv) 1505{ 1506 struct device dev; 1507 1508 int c; 1509 int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0; 1510 int drop_master = 0; 1511 int test_vsync = 0; 1512 int test_cursor = 0; 1513 char *device = NULL; 1514 char *module = NULL; 1515 unsigned int i; 1516 unsigned int count = 0, plane_count = 0; 1517 unsigned int prop_count = 0; 1518 struct pipe_arg *pipe_args = NULL; 1519 struct plane_arg *plane_args = NULL; 1520 struct property_arg *prop_args = NULL; 1521 unsigned int args = 0; 1522 int ret; 1523 1524 memset(&dev, 0, sizeof dev); 1525 1526 opterr = 0; 1527 while ((c = getopt(argc, argv, optstr)) != -1) { 1528 args++; 1529 1530 switch (c) { 1531 case 'c': 1532 connectors = 1; 1533 break; 1534 case 'D': 1535 device = optarg; 1536 args--; 1537 break; 1538 case 'd': 1539 drop_master = 1; 1540 break; 1541 case 'e': 1542 encoders = 1; 1543 break; 1544 case 'f': 1545 framebuffers = 1; 1546 break; 1547 case 'M': 1548 module = optarg; 1549 /* Preserve the default behaviour of dumping all information. */ 1550 args--; 1551 break; 1552 case 'P': 1553 plane_args = realloc(plane_args, 1554 (plane_count + 1) * sizeof *plane_args); 1555 if (plane_args == NULL) { 1556 fprintf(stderr, "memory allocation failed\n"); 1557 return 1; 1558 } 1559 memset(&plane_args[plane_count], 0, sizeof(*plane_args)); 1560 1561 if (parse_plane(&plane_args[plane_count], optarg) < 0) 1562 usage(argv[0]); 1563 1564 plane_count++; 1565 break; 1566 case 'p': 1567 crtcs = 1; 1568 planes = 1; 1569 break; 1570 case 's': 1571 pipe_args = realloc(pipe_args, 1572 (count + 1) * sizeof *pipe_args); 1573 if (pipe_args == NULL) { 1574 fprintf(stderr, "memory allocation failed\n"); 1575 return 1; 1576 } 1577 memset(&pipe_args[count], 0, sizeof(*pipe_args)); 1578 1579 if (parse_connector(&pipe_args[count], optarg) < 0) 1580 usage(argv[0]); 1581 1582 count++; 1583 break; 1584 case 'C': 1585 test_cursor = 1; 1586 break; 1587 case 'v': 1588 test_vsync = 1; 1589 break; 1590 case 'w': 1591 prop_args = realloc(prop_args, 1592 (prop_count + 1) * sizeof *prop_args); 1593 if (prop_args == NULL) { 1594 fprintf(stderr, "memory allocation failed\n"); 1595 return 1; 1596 } 1597 memset(&prop_args[prop_count], 0, sizeof(*prop_args)); 1598 1599 if (parse_property(&prop_args[prop_count], optarg) < 0) 1600 usage(argv[0]); 1601 1602 prop_count++; 1603 break; 1604 default: 1605 usage(argv[0]); 1606 break; 1607 } 1608 } 1609 1610 if (!args) 1611 encoders = connectors = crtcs = planes = framebuffers = 1; 1612 1613 dev.fd = util_open(device, module); 1614 if (dev.fd < 0) 1615 return -1; 1616 1617 if (test_vsync && !page_flipping_supported()) { 1618 fprintf(stderr, "page flipping not supported by drm.\n"); 1619 return -1; 1620 } 1621 1622 if (test_vsync && !count) { 1623 fprintf(stderr, "page flipping requires at least one -s option.\n"); 1624 return -1; 1625 } 1626 1627 if (test_cursor && !cursor_supported()) { 1628 fprintf(stderr, "hw cursor not supported by drm.\n"); 1629 return -1; 1630 } 1631 1632 dev.resources = get_resources(&dev); 1633 if (!dev.resources) { 1634 drmClose(dev.fd); 1635 return 1; 1636 } 1637 1638 for (i = 0; i < count; i++) { 1639 if (pipe_resolve_connectors(&dev, &pipe_args[i]) < 0) { 1640 free_resources(dev.resources); 1641 drmClose(dev.fd); 1642 return 1; 1643 } 1644 } 1645 1646#define dump_resource(dev, res) if (res) dump_##res(dev) 1647 1648 dump_resource(&dev, encoders); 1649 dump_resource(&dev, connectors); 1650 dump_resource(&dev, crtcs); 1651 dump_resource(&dev, planes); 1652 dump_resource(&dev, framebuffers); 1653 1654 for (i = 0; i < prop_count; ++i) 1655 set_property(&dev, &prop_args[i]); 1656 1657 if (count || plane_count) { 1658 uint64_t cap = 0; 1659 1660 ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap); 1661 if (ret || cap == 0) { 1662 fprintf(stderr, "driver doesn't support the dumb buffer API\n"); 1663 return 1; 1664 } 1665 1666 if (count) 1667 set_mode(&dev, pipe_args, count); 1668 1669 if (plane_count) 1670 set_planes(&dev, plane_args, plane_count); 1671 1672 if (test_cursor) 1673 set_cursors(&dev, pipe_args, count); 1674 1675 if (test_vsync) 1676 test_page_flip(&dev, pipe_args, count); 1677 1678 if (drop_master) 1679 drmDropMaster(dev.fd); 1680 1681 getchar(); 1682 1683 if (test_cursor) 1684 clear_cursors(&dev); 1685 1686 bo_destroy(dev.mode.bo); 1687 } 1688 1689 free_resources(dev.resources); 1690 1691 return 0; 1692} 1693