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@lunarg.com>
28  *    Thomas Hellstrom <thellstrom@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
drm_surface_validate(struct native_surface * nsurf,uint attachment_mask,unsigned int * seq_num,struct pipe_resource ** textures,int * width,int * height)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
drm_surface_init_framebuffers(struct native_surface * nsurf,boolean need_back)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
drm_surface_flush_frontbuffer(struct native_surface * nsurf)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
drm_surface_copy_swap(struct native_surface * nsurf)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
drm_surface_swap_buffers(struct native_surface * nsurf)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
drm_surface_present(struct native_surface * nsurf,const struct native_present_control * ctrl)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
drm_surface_wait(struct native_surface * nsurf)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
drm_surface_destroy(struct native_surface * nsurf)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 *
drm_display_create_surface(struct native_display * ndpy,const struct native_config * nconf,uint width,uint height)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 *
drm_display_create_surface_from_resource(struct native_display * ndpy,struct pipe_resource * resource)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
drm_display_choose_crtc(struct native_display * ndpy,uint32_t * connectors,int num_connectors)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
drm_display_set_crtc(struct native_display * ndpy,int crtc_idx,uint32_t buffer_id,uint32_t x,uint32_t y,uint32_t * connectors,int num_connectors,drmModeModeInfoPtr mode)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
drm_display_program(struct native_display * ndpy,int crtc_idx,struct native_surface * nsurf,uint x,uint y,const struct native_connector ** nconns,int num_nconns,const struct native_mode * nmode)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 **
drm_display_get_modes(struct native_display * ndpy,const struct native_connector * nconn,int * num_modes)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 **
drm_display_get_connectors(struct native_display * ndpy,int * num_connectors,int * num_crtc)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 *
drm_display_create_scanout_surface(struct native_display * ndpy,const struct native_config * nconf,uint width,uint height)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
drm_display_fini_modeset(struct native_display * ndpy)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
drm_display_init_modeset(struct native_display * ndpy)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