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
37static boolean
38drm_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 */
62static boolean
63drm_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
121static boolean
122drm_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
135static boolean
136drm_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
154static boolean
155drm_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
195static boolean
196drm_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
222static void
223drm_surface_wait(struct native_surface *nsurf)
224{
225   struct drm_surface *drmsurf = drm_surface(nsurf);
226
227   resource_surface_wait(drmsurf->rsurf);
228}
229
230static void
231drm_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
251static struct drm_surface *
252drm_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
291struct native_surface *
292drm_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 */
330static uint32_t
331drm_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 */
386static boolean
387drm_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
447static boolean
448drm_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
518static const struct native_mode **
519drm_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
578static const struct native_connector **
579drm_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
616static struct native_surface *
617drm_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
627static 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
634void
635drm_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
681boolean
682drm_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