Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

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