1 /* 2 * Mesa 3-D graphics library 3 * Version: 7.9 4 * 5 * Copyright (C) 2010 LunarG Inc. 6 * Copyright (C) 2011 VMware Inc. All rights reserved. 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 16 * in 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 21 * THE 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 24 * DEALINGS IN THE SOFTWARE. 25 * 26 * Authors: 27 * Chia-I Wu <olv (at) lunarg.com> 28 * Thomas Hellstrom <thellstrom (at) vmware.com> 29 */ 30 31 #include "util/u_memory.h" 32 #include "util/u_inlines.h" 33 #include "egllog.h" 34 35 #include "native_drm.h" 36 37 static boolean 38 drm_surface_validate(struct native_surface *nsurf, uint attachment_mask, 39 unsigned int *seq_num, struct pipe_resource **textures, 40 int *width, int *height) 41 { 42 struct drm_surface *drmsurf = drm_surface(nsurf); 43 44 if (!resource_surface_add_resources(drmsurf->rsurf, attachment_mask)) 45 return FALSE; 46 if (textures) 47 resource_surface_get_resources(drmsurf->rsurf, textures, attachment_mask); 48 49 if (seq_num) 50 *seq_num = drmsurf->sequence_number; 51 if (width) 52 *width = drmsurf->width; 53 if (height) 54 *height = drmsurf->height; 55 56 return TRUE; 57 } 58 59 /** 60 * Add textures as DRM framebuffers. 61 */ 62 static boolean 63 drm_surface_init_framebuffers(struct native_surface *nsurf, boolean need_back) 64 { 65 struct drm_surface *drmsurf = drm_surface(nsurf); 66 struct drm_display *drmdpy = drmsurf->drmdpy; 67 int num_framebuffers = (need_back) ? 2 : 1; 68 int i, err; 69 70 for (i = 0; i < num_framebuffers; i++) { 71 struct drm_framebuffer *fb; 72 enum native_attachment natt; 73 struct winsys_handle whandle; 74 uint block_bits; 75 76 if (i == 0) { 77 fb = &drmsurf->front_fb; 78 natt = NATIVE_ATTACHMENT_FRONT_LEFT; 79 } 80 else { 81 fb = &drmsurf->back_fb; 82 natt = NATIVE_ATTACHMENT_BACK_LEFT; 83 } 84 85 if (!fb->texture) { 86 /* make sure the texture has been allocated */ 87 resource_surface_add_resources(drmsurf->rsurf, 1 << natt); 88 fb->texture = 89 resource_surface_get_single_resource(drmsurf->rsurf, natt); 90 if (!fb->texture) 91 return FALSE; 92 } 93 94 /* already initialized */ 95 if (fb->buffer_id) 96 continue; 97 98 /* TODO detect the real value */ 99 fb->is_passive = TRUE; 100 101 memset(&whandle, 0, sizeof(whandle)); 102 whandle.type = DRM_API_HANDLE_TYPE_KMS; 103 104 if (!drmdpy->base.screen->resource_get_handle(drmdpy->base.screen, 105 fb->texture, &whandle)) 106 return FALSE; 107 108 block_bits = util_format_get_blocksizebits(drmsurf->color_format); 109 err = drmModeAddFB(drmdpy->fd, drmsurf->width, drmsurf->height, 110 block_bits, block_bits, whandle.stride, whandle.handle, 111 &fb->buffer_id); 112 if (err) { 113 fb->buffer_id = 0; 114 return FALSE; 115 } 116 } 117 118 return TRUE; 119 } 120 121 static boolean 122 drm_surface_flush_frontbuffer(struct native_surface *nsurf) 123 { 124 #ifdef DRM_MODE_FEATURE_DIRTYFB 125 struct drm_surface *drmsurf = drm_surface(nsurf); 126 struct drm_display *drmdpy = drmsurf->drmdpy; 127 128 if (drmsurf->front_fb.is_passive) 129 drmModeDirtyFB(drmdpy->fd, drmsurf->front_fb.buffer_id, NULL, 0); 130 #endif 131 132 return TRUE; 133 } 134 135 static boolean 136 drm_surface_copy_swap(struct native_surface *nsurf) 137 { 138 struct drm_surface *drmsurf = drm_surface(nsurf); 139 struct drm_display *drmdpy = drmsurf->drmdpy; 140 141 (void) resource_surface_throttle(drmsurf->rsurf); 142 if (!resource_surface_copy_swap(drmsurf->rsurf, &drmdpy->base)) 143 return FALSE; 144 145 (void) resource_surface_flush(drmsurf->rsurf, &drmdpy->base); 146 if (!drm_surface_flush_frontbuffer(nsurf)) 147 return FALSE; 148 149 drmsurf->sequence_number++; 150 151 return TRUE; 152 } 153 154 static boolean 155 drm_surface_swap_buffers(struct native_surface *nsurf) 156 { 157 struct drm_surface *drmsurf = drm_surface(nsurf); 158 struct drm_crtc *drmcrtc = &drmsurf->current_crtc; 159 struct drm_display *drmdpy = drmsurf->drmdpy; 160 struct drm_framebuffer tmp_fb; 161 int err; 162 163 if (!drmsurf->have_pageflip) 164 return drm_surface_copy_swap(nsurf); 165 166 if (!drmsurf->back_fb.buffer_id) { 167 if (!drm_surface_init_framebuffers(&drmsurf->base, TRUE)) 168 return FALSE; 169 } 170 171 if (drmsurf->is_shown && drmcrtc->crtc) { 172 err = drmModePageFlip(drmdpy->fd, drmcrtc->crtc->crtc_id, 173 drmsurf->back_fb.buffer_id, 0, NULL); 174 if (err) { 175 drmsurf->have_pageflip = FALSE; 176 return drm_surface_copy_swap(nsurf); 177 } 178 } 179 180 /* swap the buffers */ 181 tmp_fb = drmsurf->front_fb; 182 drmsurf->front_fb = drmsurf->back_fb; 183 drmsurf->back_fb = tmp_fb; 184 185 resource_surface_swap_buffers(drmsurf->rsurf, 186 NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, FALSE); 187 /* the front/back textures are swapped */ 188 drmsurf->sequence_number++; 189 drmdpy->event_handler->invalid_surface(&drmdpy->base, 190 &drmsurf->base, drmsurf->sequence_number); 191 192 return TRUE; 193 } 194 195 static boolean 196 drm_surface_present(struct native_surface *nsurf, 197 const struct native_present_control *ctrl) 198 { 199 boolean ret; 200 201 if (ctrl->swap_interval) 202 return FALSE; 203 204 switch (ctrl->natt) { 205 case NATIVE_ATTACHMENT_FRONT_LEFT: 206 ret = drm_surface_flush_frontbuffer(nsurf); 207 break; 208 case NATIVE_ATTACHMENT_BACK_LEFT: 209 if (ctrl->preserve) 210 ret = drm_surface_copy_swap(nsurf); 211 else 212 ret = drm_surface_swap_buffers(nsurf); 213 break; 214 default: 215 ret = FALSE; 216 break; 217 } 218 219 return ret; 220 } 221 222 static void 223 drm_surface_wait(struct native_surface *nsurf) 224 { 225 struct drm_surface *drmsurf = drm_surface(nsurf); 226 227 resource_surface_wait(drmsurf->rsurf); 228 } 229 230 static void 231 drm_surface_destroy(struct native_surface *nsurf) 232 { 233 struct drm_surface *drmsurf = drm_surface(nsurf); 234 235 resource_surface_wait(drmsurf->rsurf); 236 if (drmsurf->current_crtc.crtc) 237 drmModeFreeCrtc(drmsurf->current_crtc.crtc); 238 239 if (drmsurf->front_fb.buffer_id) 240 drmModeRmFB(drmsurf->drmdpy->fd, drmsurf->front_fb.buffer_id); 241 pipe_resource_reference(&drmsurf->front_fb.texture, NULL); 242 243 if (drmsurf->back_fb.buffer_id) 244 drmModeRmFB(drmsurf->drmdpy->fd, drmsurf->back_fb.buffer_id); 245 pipe_resource_reference(&drmsurf->back_fb.texture, NULL); 246 247 resource_surface_destroy(drmsurf->rsurf); 248 FREE(drmsurf); 249 } 250 251 static struct drm_surface * 252 drm_display_create_surface(struct native_display *ndpy, 253 const struct native_config *nconf, 254 uint width, uint height) 255 { 256 struct drm_display *drmdpy = drm_display(ndpy); 257 struct drm_config *drmconf = drm_config(nconf); 258 struct drm_surface *drmsurf; 259 260 drmsurf = CALLOC_STRUCT(drm_surface); 261 if (!drmsurf) 262 return NULL; 263 264 drmsurf->drmdpy = drmdpy; 265 drmsurf->color_format = drmconf->base.color_format; 266 drmsurf->width = width; 267 drmsurf->height = height; 268 drmsurf->have_pageflip = TRUE; 269 270 drmsurf->rsurf = resource_surface_create(drmdpy->base.screen, 271 drmsurf->color_format, 272 PIPE_BIND_RENDER_TARGET | 273 PIPE_BIND_SAMPLER_VIEW | 274 PIPE_BIND_DISPLAY_TARGET | 275 PIPE_BIND_SCANOUT); 276 if (!drmsurf->rsurf) { 277 FREE(drmsurf); 278 return NULL; 279 } 280 281 resource_surface_set_size(drmsurf->rsurf, drmsurf->width, drmsurf->height); 282 283 drmsurf->base.destroy = drm_surface_destroy; 284 drmsurf->base.present = drm_surface_present; 285 drmsurf->base.validate = drm_surface_validate; 286 drmsurf->base.wait = drm_surface_wait; 287 288 return drmsurf; 289 } 290 291 struct native_surface * 292 drm_display_create_surface_from_resource(struct native_display *ndpy, 293 struct pipe_resource *resource) 294 { 295 struct drm_display *drmdpy = drm_display(ndpy); 296 struct drm_surface *drmsurf; 297 enum native_attachment natt = NATIVE_ATTACHMENT_FRONT_LEFT; 298 299 drmsurf = CALLOC_STRUCT(drm_surface); 300 if (!drmsurf) 301 return NULL; 302 303 drmsurf->drmdpy = drmdpy; 304 drmsurf->color_format = resource->format; 305 drmsurf->width = resource->width0; 306 drmsurf->height = resource->height0; 307 drmsurf->have_pageflip = FALSE; 308 309 drmsurf->rsurf = resource_surface_create(drmdpy->base.screen, 310 drmsurf->color_format, 311 PIPE_BIND_RENDER_TARGET | 312 PIPE_BIND_SAMPLER_VIEW | 313 PIPE_BIND_DISPLAY_TARGET | 314 PIPE_BIND_SCANOUT); 315 316 resource_surface_import_resource(drmsurf->rsurf, natt, resource); 317 318 drmsurf->base.destroy = drm_surface_destroy; 319 drmsurf->base.present = drm_surface_present; 320 drmsurf->base.validate = drm_surface_validate; 321 drmsurf->base.wait = drm_surface_wait; 322 323 return &drmsurf->base; 324 } 325 326 327 /** 328 * Choose a CRTC that supports all given connectors. 329 */ 330 static uint32_t 331 drm_display_choose_crtc(struct native_display *ndpy, 332 uint32_t *connectors, int num_connectors) 333 { 334 struct drm_display *drmdpy = drm_display(ndpy); 335 int idx; 336 337 for (idx = 0; idx < drmdpy->resources->count_crtcs; idx++) { 338 boolean found_crtc = TRUE; 339 int i, j; 340 341 for (i = 0; i < num_connectors; i++) { 342 drmModeConnectorPtr connector; 343 int encoder_idx = -1; 344 345 connector = drmModeGetConnector(drmdpy->fd, connectors[i]); 346 if (!connector) { 347 found_crtc = FALSE; 348 break; 349 } 350 351 /* find an encoder the CRTC supports */ 352 for (j = 0; j < connector->count_encoders; j++) { 353 drmModeEncoderPtr encoder = 354 drmModeGetEncoder(drmdpy->fd, connector->encoders[j]); 355 if (encoder->possible_crtcs & (1 << idx)) { 356 encoder_idx = j; 357 break; 358 } 359 drmModeFreeEncoder(encoder); 360 } 361 362 drmModeFreeConnector(connector); 363 if (encoder_idx < 0) { 364 found_crtc = FALSE; 365 break; 366 } 367 } 368 369 if (found_crtc) 370 break; 371 } 372 373 if (idx >= drmdpy->resources->count_crtcs) { 374 _eglLog(_EGL_WARNING, 375 "failed to find a CRTC that supports the given %d connectors", 376 num_connectors); 377 return 0; 378 } 379 380 return drmdpy->resources->crtcs[idx]; 381 } 382 383 /** 384 * Remember the original CRTC status and set the CRTC 385 */ 386 static boolean 387 drm_display_set_crtc(struct native_display *ndpy, int crtc_idx, 388 uint32_t buffer_id, uint32_t x, uint32_t y, 389 uint32_t *connectors, int num_connectors, 390 drmModeModeInfoPtr mode) 391 { 392 struct drm_display *drmdpy = drm_display(ndpy); 393 struct drm_crtc *drmcrtc = &drmdpy->saved_crtcs[crtc_idx]; 394 uint32_t crtc_id; 395 int err; 396 397 if (drmcrtc->crtc) { 398 crtc_id = drmcrtc->crtc->crtc_id; 399 } 400 else { 401 int count = 0, i; 402 403 /* 404 * Choose the CRTC once. It could be more dynamic, but let's keep it 405 * simple for now. 406 */ 407 crtc_id = drm_display_choose_crtc(&drmdpy->base, 408 connectors, num_connectors); 409 410 /* save the original CRTC status */ 411 drmcrtc->crtc = drmModeGetCrtc(drmdpy->fd, crtc_id); 412 if (!drmcrtc->crtc) 413 return FALSE; 414 415 for (i = 0; i < drmdpy->num_connectors; i++) { 416 struct drm_connector *drmconn = &drmdpy->connectors[i]; 417 drmModeConnectorPtr connector = drmconn->connector; 418 drmModeEncoderPtr encoder; 419 420 encoder = drmModeGetEncoder(drmdpy->fd, connector->encoder_id); 421 if (encoder) { 422 if (encoder->crtc_id == crtc_id) { 423 drmcrtc->connectors[count++] = connector->connector_id; 424 if (count >= Elements(drmcrtc->connectors)) 425 break; 426 } 427 drmModeFreeEncoder(encoder); 428 } 429 } 430 431 drmcrtc->num_connectors = count; 432 } 433 434 err = drmModeSetCrtc(drmdpy->fd, crtc_id, buffer_id, x, y, 435 connectors, num_connectors, mode); 436 if (err) { 437 drmModeFreeCrtc(drmcrtc->crtc); 438 drmcrtc->crtc = NULL; 439 drmcrtc->num_connectors = 0; 440 441 return FALSE; 442 } 443 444 return TRUE; 445 } 446 447 static boolean 448 drm_display_program(struct native_display *ndpy, int crtc_idx, 449 struct native_surface *nsurf, uint x, uint y, 450 const struct native_connector **nconns, int num_nconns, 451 const struct native_mode *nmode) 452 { 453 struct drm_display *drmdpy = drm_display(ndpy); 454 struct drm_surface *drmsurf = drm_surface(nsurf); 455 const struct drm_mode *drmmode = drm_mode(nmode); 456 uint32_t connector_ids[32]; 457 uint32_t buffer_id; 458 drmModeModeInfo mode_tmp, *mode; 459 int i; 460 461 if (num_nconns > Elements(connector_ids)) { 462 _eglLog(_EGL_WARNING, "too many connectors (%d)", num_nconns); 463 num_nconns = Elements(connector_ids); 464 } 465 466 if (drmsurf) { 467 if (!drm_surface_init_framebuffers(&drmsurf->base, FALSE)) 468 return FALSE; 469 470 buffer_id = drmsurf->front_fb.buffer_id; 471 /* the mode argument of drmModeSetCrtc is not constified */ 472 mode_tmp = drmmode->mode; 473 mode = &mode_tmp; 474 } 475 else { 476 /* disable the CRTC */ 477 buffer_id = 0; 478 mode = NULL; 479 num_nconns = 0; 480 } 481 482 for (i = 0; i < num_nconns; i++) { 483 struct drm_connector *drmconn = drm_connector(nconns[i]); 484 connector_ids[i] = drmconn->connector->connector_id; 485 } 486 487 if (!drm_display_set_crtc(&drmdpy->base, crtc_idx, buffer_id, x, y, 488 connector_ids, num_nconns, mode)) { 489 _eglLog(_EGL_WARNING, "failed to set CRTC %d", crtc_idx); 490 491 return FALSE; 492 } 493 494 if (drmdpy->shown_surfaces[crtc_idx]) 495 drmdpy->shown_surfaces[crtc_idx]->is_shown = FALSE; 496 drmdpy->shown_surfaces[crtc_idx] = drmsurf; 497 498 /* remember the settings for buffer swapping */ 499 if (drmsurf) { 500 uint32_t crtc_id = drmdpy->saved_crtcs[crtc_idx].crtc->crtc_id; 501 struct drm_crtc *drmcrtc = &drmsurf->current_crtc; 502 503 if (drmcrtc->crtc) 504 drmModeFreeCrtc(drmcrtc->crtc); 505 drmcrtc->crtc = drmModeGetCrtc(drmdpy->fd, crtc_id); 506 507 assert(num_nconns < Elements(drmcrtc->connectors)); 508 memcpy(drmcrtc->connectors, connector_ids, 509 sizeof(*connector_ids) * num_nconns); 510 drmcrtc->num_connectors = num_nconns; 511 512 drmsurf->is_shown = TRUE; 513 } 514 515 return TRUE; 516 } 517 518 static const struct native_mode ** 519 drm_display_get_modes(struct native_display *ndpy, 520 const struct native_connector *nconn, 521 int *num_modes) 522 { 523 struct drm_display *drmdpy = drm_display(ndpy); 524 struct drm_connector *drmconn = drm_connector(nconn); 525 const struct native_mode **nmodes_return; 526 int count, i; 527 528 /* delete old data */ 529 if (drmconn->connector) { 530 drmModeFreeConnector(drmconn->connector); 531 FREE(drmconn->drm_modes); 532 533 drmconn->connector = NULL; 534 drmconn->drm_modes = NULL; 535 drmconn->num_modes = 0; 536 } 537 538 /* detect again */ 539 drmconn->connector = drmModeGetConnector(drmdpy->fd, drmconn->connector_id); 540 if (!drmconn->connector) 541 return NULL; 542 543 count = drmconn->connector->count_modes; 544 drmconn->drm_modes = CALLOC(count, sizeof(*drmconn->drm_modes)); 545 if (!drmconn->drm_modes) { 546 drmModeFreeConnector(drmconn->connector); 547 drmconn->connector = NULL; 548 549 return NULL; 550 } 551 552 for (i = 0; i < count; i++) { 553 struct drm_mode *drmmode = &drmconn->drm_modes[i]; 554 drmModeModeInfoPtr mode = &drmconn->connector->modes[i]; 555 556 drmmode->mode = *mode; 557 558 drmmode->base.desc = drmmode->mode.name; 559 drmmode->base.width = drmmode->mode.hdisplay; 560 drmmode->base.height = drmmode->mode.vdisplay; 561 drmmode->base.refresh_rate = drmmode->mode.vrefresh; 562 /* not all kernels have vrefresh = refresh_rate * 1000 */ 563 if (drmmode->base.refresh_rate < 1000) 564 drmmode->base.refresh_rate *= 1000; 565 } 566 567 nmodes_return = MALLOC(count * sizeof(*nmodes_return)); 568 if (nmodes_return) { 569 for (i = 0; i < count; i++) 570 nmodes_return[i] = &drmconn->drm_modes[i].base; 571 if (num_modes) 572 *num_modes = count; 573 } 574 575 return nmodes_return; 576 } 577 578 static const struct native_connector ** 579 drm_display_get_connectors(struct native_display *ndpy, int *num_connectors, 580 int *num_crtc) 581 { 582 struct drm_display *drmdpy = drm_display(ndpy); 583 const struct native_connector **connectors; 584 int i; 585 586 if (!drmdpy->connectors) { 587 drmdpy->connectors = 588 CALLOC(drmdpy->resources->count_connectors, sizeof(*drmdpy->connectors)); 589 if (!drmdpy->connectors) 590 return NULL; 591 592 for (i = 0; i < drmdpy->resources->count_connectors; i++) { 593 struct drm_connector *drmconn = &drmdpy->connectors[i]; 594 595 drmconn->connector_id = drmdpy->resources->connectors[i]; 596 /* drmconn->connector is allocated when the modes are asked */ 597 } 598 599 drmdpy->num_connectors = drmdpy->resources->count_connectors; 600 } 601 602 connectors = MALLOC(drmdpy->num_connectors * sizeof(*connectors)); 603 if (connectors) { 604 for (i = 0; i < drmdpy->num_connectors; i++) 605 connectors[i] = &drmdpy->connectors[i].base; 606 if (num_connectors) 607 *num_connectors = drmdpy->num_connectors; 608 } 609 610 if (num_crtc) 611 *num_crtc = drmdpy->resources->count_crtcs; 612 613 return connectors; 614 } 615 616 static struct native_surface * 617 drm_display_create_scanout_surface(struct native_display *ndpy, 618 const struct native_config *nconf, 619 uint width, uint height) 620 { 621 struct drm_surface *drmsurf; 622 623 drmsurf = drm_display_create_surface(ndpy, nconf, width, height); 624 return &drmsurf->base; 625 } 626 627 static struct native_display_modeset drm_display_modeset = { 628 .get_connectors = drm_display_get_connectors, 629 .get_modes = drm_display_get_modes, 630 .create_scanout_surface = drm_display_create_scanout_surface, 631 .program = drm_display_program 632 }; 633 634 void 635 drm_display_fini_modeset(struct native_display *ndpy) 636 { 637 struct drm_display *drmdpy = drm_display(ndpy); 638 int i; 639 640 if (drmdpy->connectors) { 641 for (i = 0; i < drmdpy->num_connectors; i++) { 642 struct drm_connector *drmconn = &drmdpy->connectors[i]; 643 if (drmconn->connector) { 644 drmModeFreeConnector(drmconn->connector); 645 FREE(drmconn->drm_modes); 646 } 647 } 648 FREE(drmdpy->connectors); 649 } 650 651 if (drmdpy->shown_surfaces) { 652 FREE(drmdpy->shown_surfaces); 653 drmdpy->shown_surfaces = NULL; 654 } 655 656 if (drmdpy->saved_crtcs) { 657 for (i = 0; i < drmdpy->resources->count_crtcs; i++) { 658 struct drm_crtc *drmcrtc = &drmdpy->saved_crtcs[i]; 659 660 if (drmcrtc->crtc) { 661 /* restore crtc */ 662 drmModeSetCrtc(drmdpy->fd, drmcrtc->crtc->crtc_id, 663 drmcrtc->crtc->buffer_id, drmcrtc->crtc->x, drmcrtc->crtc->y, 664 drmcrtc->connectors, drmcrtc->num_connectors, 665 &drmcrtc->crtc->mode); 666 667 drmModeFreeCrtc(drmcrtc->crtc); 668 } 669 } 670 FREE(drmdpy->saved_crtcs); 671 } 672 673 if (drmdpy->resources) { 674 drmModeFreeResources(drmdpy->resources); 675 drmdpy->resources = NULL; 676 } 677 678 drmdpy->base.modeset = NULL; 679 } 680 681 boolean 682 drm_display_init_modeset(struct native_display *ndpy) 683 { 684 struct drm_display *drmdpy = drm_display(ndpy); 685 686 /* resources are fixed, unlike crtc, connector, or encoder */ 687 drmdpy->resources = drmModeGetResources(drmdpy->fd); 688 if (!drmdpy->resources) { 689 _eglLog(_EGL_DEBUG, "Failed to get KMS resources. Disable modeset."); 690 return FALSE; 691 } 692 693 drmdpy->saved_crtcs = 694 CALLOC(drmdpy->resources->count_crtcs, sizeof(*drmdpy->saved_crtcs)); 695 if (!drmdpy->saved_crtcs) { 696 drm_display_fini_modeset(&drmdpy->base); 697 return FALSE; 698 } 699 700 drmdpy->shown_surfaces = 701 CALLOC(drmdpy->resources->count_crtcs, sizeof(*drmdpy->shown_surfaces)); 702 if (!drmdpy->shown_surfaces) { 703 drm_display_fini_modeset(&drmdpy->base); 704 return FALSE; 705 } 706 707 drmdpy->base.modeset = &drm_display_modeset; 708 709 return TRUE; 710 } 711