Home | History | Annotate | Download | only in drm
      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