1 /*
2  * Cogl
3  *
4  * A Low Level GPU Graphics and Utilities API
5  *
6  * Copyright (C) 2011 Intel Corporation.
7  *
8  * Permission is hereby granted, free of charge, to any person
9  * obtaining a copy of this software and associated documentation
10  * files (the "Software"), to deal in the Software without
11  * restriction, including without limitation the rights to use, copy,
12  * modify, merge, publish, distribute, sublicense, and/or sell copies
13  * of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be
17  * included in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26  * SOFTWARE.
27  *
28  *
29  * Authors:
30  *   Rob Bradford <rob@linux.intel.com>
31  *   Kristian Høgsberg (from eglkms.c)
32  *   Benjamin Franzke (from eglkms.c)
33  *   Robert Bragg <robert@linux.intel.com>
34  *   Neil Roberts <neil@linux.intel.com>
35  */
36 
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40 
41 #include <EGL/egl.h>
42 #include <EGL/eglext.h>
43 #include <errno.h>
44 #include <stddef.h>
45 #include <drm.h>
46 #include <xf86drm.h>
47 #include <xf86drmMode.h>
48 #include <gbm.h>
49 #include <glib.h>
50 #include <sys/fcntl.h>
51 #include <unistd.h>
52 #include <string.h>
53 #include <stdlib.h>
54 
55 #include "cogl-winsys-egl-kms-private.h"
56 #include "cogl-winsys-egl-private.h"
57 #include "cogl-renderer-private.h"
58 #include "cogl-framebuffer-private.h"
59 #include "cogl-onscreen-private.h"
60 #include "cogl-kms-renderer.h"
61 #include "cogl-kms-display.h"
62 #include "cogl-version.h"
63 #include "cogl-error-private.h"
64 #include "cogl-poll-private.h"
65 
66 static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable;
67 
68 static const CoglWinsysVtable *parent_vtable;
69 
70 typedef struct _CoglRendererKMS
71 {
72   int fd;
73   int opened_fd;
74   struct gbm_device *gbm;
75   CoglClosure *swap_notify_idle;
76   CoglBool     page_flips_not_supported;
77 } CoglRendererKMS;
78 
79 typedef struct _CoglOutputKMS
80 {
81   drmModeConnector *connector;
82   drmModeEncoder *encoder;
83   drmModeCrtc *saved_crtc;
84   drmModeModeInfo *modes;
85   int n_modes;
86   drmModeModeInfo mode;
87 } CoglOutputKMS;
88 
89 typedef struct _CoglDisplayKMS
90 {
91   GList *outputs;
92   GList *crtcs;
93 
94   int width, height;
95   CoglBool pending_set_crtc;
96   struct gbm_surface *dummy_gbm_surface;
97 
98   CoglOnscreen *onscreen;
99 } CoglDisplayKMS;
100 
101 typedef struct _CoglFlipKMS
102 {
103   CoglOnscreen *onscreen;
104   int pending;
105 } CoglFlipKMS;
106 
107 typedef struct _CoglOnscreenKMS
108 {
109   struct gbm_surface *surface;
110   uint32_t current_fb_id;
111   uint32_t next_fb_id;
112   struct gbm_bo *current_bo;
113   struct gbm_bo *next_bo;
114   CoglBool pending_swap_notify;
115 
116   EGLSurface *pending_egl_surface;
117   struct gbm_surface *pending_surface;
118 } CoglOnscreenKMS;
119 
120 static const char device_name[] = "/dev/dri/card0";
121 
122 static void
_cogl_winsys_renderer_disconnect(CoglRenderer * renderer)123 _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
124 {
125   CoglRendererEGL *egl_renderer = renderer->winsys;
126   CoglRendererKMS *kms_renderer = egl_renderer->platform;
127 
128   if (egl_renderer->edpy != EGL_NO_DISPLAY)
129     eglTerminate (egl_renderer->edpy);
130 
131   if (kms_renderer->gbm != NULL)
132     gbm_device_destroy (kms_renderer->gbm);
133 
134   if (kms_renderer->opened_fd >= 0)
135     close (kms_renderer->opened_fd);
136 
137   g_slice_free (CoglRendererKMS, kms_renderer);
138   g_slice_free (CoglRendererEGL, egl_renderer);
139 }
140 
141 static void
flush_pending_swap_notify_cb(void * data,void * user_data)142 flush_pending_swap_notify_cb (void *data,
143                               void *user_data)
144 {
145   CoglFramebuffer *framebuffer = data;
146 
147   if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
148     {
149       CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
150       CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
151       CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
152 
153       if (kms_onscreen->pending_swap_notify)
154         {
155           CoglFrameInfo *info = g_queue_pop_head (&onscreen->pending_frame_infos);
156 
157           _cogl_onscreen_notify_frame_sync (onscreen, info);
158           _cogl_onscreen_notify_complete (onscreen, info);
159           kms_onscreen->pending_swap_notify = FALSE;
160 
161           cogl_object_unref (info);
162         }
163     }
164 }
165 
166 static void
flush_pending_swap_notify_idle(void * user_data)167 flush_pending_swap_notify_idle (void *user_data)
168 {
169   CoglContext *context = user_data;
170   CoglRendererEGL *egl_renderer = context->display->renderer->winsys;
171   CoglRendererKMS *kms_renderer = egl_renderer->platform;
172 
173   /* This needs to be disconnected before invoking the callbacks in
174    * case the callbacks cause it to be queued again */
175   _cogl_closure_disconnect (kms_renderer->swap_notify_idle);
176   kms_renderer->swap_notify_idle = NULL;
177 
178   g_list_foreach (context->framebuffers,
179                   flush_pending_swap_notify_cb,
180                   NULL);
181 }
182 
183 static void
free_current_bo(CoglOnscreen * onscreen)184 free_current_bo (CoglOnscreen *onscreen)
185 {
186   CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
187   CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
188   CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
189   CoglRenderer *renderer = context->display->renderer;
190   CoglRendererEGL *egl_renderer = renderer->winsys;
191   CoglRendererKMS *kms_renderer = egl_renderer->platform;
192 
193   if (kms_onscreen->current_fb_id)
194     {
195       drmModeRmFB (kms_renderer->fd,
196                    kms_onscreen->current_fb_id);
197       kms_onscreen->current_fb_id = 0;
198     }
199   if (kms_onscreen->current_bo)
200     {
201       gbm_surface_release_buffer (kms_onscreen->surface,
202                                   kms_onscreen->current_bo);
203       kms_onscreen->current_bo = NULL;
204     }
205 }
206 
207 static void
queue_swap_notify_for_onscreen(CoglOnscreen * onscreen)208 queue_swap_notify_for_onscreen (CoglOnscreen *onscreen)
209 {
210   CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
211   CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
212   CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
213   CoglRenderer *renderer = context->display->renderer;
214   CoglRendererEGL *egl_renderer = renderer->winsys;
215   CoglRendererKMS *kms_renderer = egl_renderer->platform;
216 
217   /* We only want to notify that the swap is complete when the
218    * application calls cogl_context_dispatch so instead of
219    * immediately notifying we queue an idle callback */
220   if (!kms_renderer->swap_notify_idle)
221     {
222       kms_renderer->swap_notify_idle =
223         _cogl_poll_renderer_add_idle (renderer,
224                                       flush_pending_swap_notify_idle,
225                                       context,
226                                       NULL);
227     }
228 
229   kms_onscreen->pending_swap_notify = TRUE;
230 }
231 
232 static void
process_flip(CoglFlipKMS * flip)233 process_flip (CoglFlipKMS *flip)
234 {
235   /* We're only ready to dispatch a swap notification once all outputs
236    * have flipped... */
237   flip->pending--;
238   if (flip->pending == 0)
239     {
240       CoglOnscreen *onscreen = flip->onscreen;
241       CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
242       CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
243 
244       queue_swap_notify_for_onscreen (onscreen);
245 
246       free_current_bo (onscreen);
247 
248       kms_onscreen->current_fb_id = kms_onscreen->next_fb_id;
249       kms_onscreen->next_fb_id = 0;
250 
251       kms_onscreen->current_bo = kms_onscreen->next_bo;
252       kms_onscreen->next_bo = NULL;
253 
254       cogl_object_unref (flip->onscreen);
255 
256       g_slice_free (CoglFlipKMS, flip);
257     }
258 }
259 
260 static void
page_flip_handler(int fd,unsigned int frame,unsigned int sec,unsigned int usec,void * data)261 page_flip_handler (int fd,
262                    unsigned int frame,
263                    unsigned int sec,
264                    unsigned int usec,
265                    void *data)
266 {
267   CoglFlipKMS *flip = data;
268 
269   process_flip (flip);
270 }
271 
272 static void
handle_drm_event(CoglRendererKMS * kms_renderer)273 handle_drm_event (CoglRendererKMS *kms_renderer)
274 {
275   drmEventContext evctx;
276 
277   if (kms_renderer->page_flips_not_supported)
278     return;
279 
280   memset (&evctx, 0, sizeof evctx);
281   evctx.version = DRM_EVENT_CONTEXT_VERSION;
282   evctx.page_flip_handler = page_flip_handler;
283   drmHandleEvent (kms_renderer->fd, &evctx);
284 }
285 
286 static void
dispatch_kms_events(void * user_data,int revents)287 dispatch_kms_events (void *user_data, int revents)
288 {
289   CoglRenderer *renderer = user_data;
290   CoglRendererEGL *egl_renderer = renderer->winsys;
291   CoglRendererKMS *kms_renderer = egl_renderer->platform;
292 
293   if (!revents)
294     return;
295 
296   handle_drm_event (kms_renderer);
297 }
298 
299 static CoglBool
_cogl_winsys_renderer_connect(CoglRenderer * renderer,CoglError ** error)300 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
301                                CoglError **error)
302 {
303   CoglRendererEGL *egl_renderer;
304   CoglRendererKMS *kms_renderer;
305 
306   renderer->winsys = g_slice_new0 (CoglRendererEGL);
307   egl_renderer = renderer->winsys;
308 
309   egl_renderer->platform_vtable = &_cogl_winsys_egl_vtable;
310   egl_renderer->platform = g_slice_new0 (CoglRendererKMS);
311   kms_renderer = egl_renderer->platform;
312 
313   kms_renderer->fd = -1;
314   kms_renderer->opened_fd = -1;
315 
316   egl_renderer->edpy = EGL_NO_DISPLAY;
317 
318   if (renderer->kms_fd >= 0)
319     {
320       kms_renderer->fd = renderer->kms_fd;
321     }
322   else
323     {
324       kms_renderer->opened_fd = open (device_name, O_RDWR);
325       kms_renderer->fd = kms_renderer->opened_fd;
326       if (kms_renderer->fd < 0)
327         {
328           /* Probably permissions error */
329           _cogl_set_error (error, COGL_WINSYS_ERROR,
330                            COGL_WINSYS_ERROR_INIT,
331                            "Couldn't open %s", device_name);
332           return FALSE;
333         }
334     }
335 
336   kms_renderer->gbm = gbm_create_device (kms_renderer->fd);
337   if (kms_renderer->gbm == NULL)
338     {
339       _cogl_set_error (error, COGL_WINSYS_ERROR,
340                    COGL_WINSYS_ERROR_INIT,
341                    "Couldn't create gbm device");
342       goto fail;
343     }
344 
345   egl_renderer->edpy = eglGetDisplay ((EGLNativeDisplayType)kms_renderer->gbm);
346   if (egl_renderer->edpy == EGL_NO_DISPLAY)
347     {
348       _cogl_set_error (error, COGL_WINSYS_ERROR,
349                    COGL_WINSYS_ERROR_INIT,
350                    "Couldn't get eglDisplay");
351       goto fail;
352     }
353 
354   if (!_cogl_winsys_egl_renderer_connect_common (renderer, error))
355     goto fail;
356 
357   _cogl_poll_renderer_add_fd (renderer,
358                               kms_renderer->fd,
359                               COGL_POLL_FD_EVENT_IN,
360                               NULL, /* no prepare callback */
361                               dispatch_kms_events,
362                               renderer);
363 
364   return TRUE;
365 
366 fail:
367   _cogl_winsys_renderer_disconnect (renderer);
368 
369   return FALSE;
370 }
371 
372 static CoglBool
is_connector_excluded(int id,int * excluded_connectors,int n_excluded_connectors)373 is_connector_excluded (int id,
374                        int *excluded_connectors,
375                        int n_excluded_connectors)
376 {
377   int i;
378   for (i = 0; i < n_excluded_connectors; i++)
379     if (excluded_connectors[i] == id)
380       return TRUE;
381   return FALSE;
382 }
383 
384 static drmModeConnector *
find_connector(int fd,drmModeRes * resources,int * excluded_connectors,int n_excluded_connectors)385 find_connector (int fd,
386                 drmModeRes *resources,
387                 int *excluded_connectors,
388                 int n_excluded_connectors)
389 {
390   int i;
391 
392   for (i = 0; i < resources->count_connectors; i++)
393     {
394       drmModeConnector *connector =
395         drmModeGetConnector (fd, resources->connectors[i]);
396 
397       if (connector &&
398           connector->connection == DRM_MODE_CONNECTED &&
399           connector->count_modes > 0 &&
400           !is_connector_excluded (connector->connector_id,
401                                   excluded_connectors,
402                                   n_excluded_connectors))
403         return connector;
404       drmModeFreeConnector(connector);
405     }
406   return NULL;
407 }
408 
409 static CoglBool
find_mirror_modes(drmModeModeInfo * modes0,int n_modes0,drmModeModeInfo * modes1,int n_modes1,drmModeModeInfo * mode1_out,drmModeModeInfo * mode0_out)410 find_mirror_modes (drmModeModeInfo *modes0,
411                    int n_modes0,
412                    drmModeModeInfo *modes1,
413                    int n_modes1,
414                    drmModeModeInfo *mode1_out,
415                    drmModeModeInfo *mode0_out)
416 {
417   int i;
418   for (i = 0; i < n_modes0; i++)
419     {
420       int j;
421       drmModeModeInfo *mode0 = &modes0[i];
422       for (j = 0; j < n_modes1; j++)
423         {
424           drmModeModeInfo *mode1 = &modes1[j];
425           if (mode1->hdisplay == mode0->hdisplay &&
426               mode1->vdisplay == mode0->vdisplay)
427             {
428               *mode0_out = *mode0;
429               *mode1_out = *mode1;
430               return TRUE;
431             }
432         }
433     }
434   return FALSE;
435 }
436 
437 static drmModeModeInfo builtin_1024x768 =
438 {
439         63500,                        /* clock */
440         1024, 1072, 1176, 1328, 0,
441         768, 771, 775, 798, 0,
442         59920,
443         DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC,
444         0,
445         "1024x768"
446 };
447 
448 static CoglBool
is_panel(int type)449 is_panel (int type)
450 {
451   return (type == DRM_MODE_CONNECTOR_LVDS ||
452           type == DRM_MODE_CONNECTOR_eDP);
453 }
454 
455 static CoglOutputKMS *
find_output(int _index,int fd,drmModeRes * resources,int * excluded_connectors,int n_excluded_connectors,CoglError ** error)456 find_output (int _index,
457              int fd,
458              drmModeRes *resources,
459              int *excluded_connectors,
460              int n_excluded_connectors,
461              CoglError **error)
462 {
463   char *connector_env_name = g_strdup_printf ("COGL_KMS_CONNECTOR%d", _index);
464   char *mode_env_name;
465   drmModeConnector *connector;
466   drmModeEncoder *encoder;
467   CoglOutputKMS *output;
468   drmModeModeInfo *modes;
469   int n_modes;
470 
471   if (getenv (connector_env_name))
472     {
473       unsigned long id = strtoul (getenv (connector_env_name), NULL, 10);
474       connector = drmModeGetConnector (fd, id);
475     }
476   else
477     connector = NULL;
478   g_free (connector_env_name);
479 
480   if (connector == NULL)
481     connector = find_connector (fd, resources,
482                                 excluded_connectors, n_excluded_connectors);
483   if (connector == NULL)
484     {
485       _cogl_set_error (error, COGL_WINSYS_ERROR,
486                    COGL_WINSYS_ERROR_INIT,
487                    "No currently active connector found");
488       return NULL;
489     }
490 
491   /* XXX: At this point it seems connector->encoder_id may be an invalid id of 0
492    * even though the connector is marked as connected. Referencing ->encoders[0]
493    * seems more reliable. */
494   encoder = drmModeGetEncoder (fd, connector->encoders[0]);
495 
496   output = g_slice_new0 (CoglOutputKMS);
497   output->connector = connector;
498   output->encoder = encoder;
499   output->saved_crtc = drmModeGetCrtc (fd, encoder->crtc_id);
500 
501   if (is_panel (connector->connector_type))
502     {
503       n_modes = connector->count_modes + 1;
504       modes = g_new (drmModeModeInfo, n_modes);
505       memcpy (modes, connector->modes,
506               sizeof (drmModeModeInfo) * connector->count_modes);
507       /* TODO: parse EDID */
508       modes[n_modes - 1] = builtin_1024x768;
509     }
510   else
511     {
512       n_modes = connector->count_modes;
513       modes = g_new (drmModeModeInfo, n_modes);
514       memcpy (modes, connector->modes,
515               sizeof (drmModeModeInfo) * n_modes);
516     }
517 
518   mode_env_name = g_strdup_printf ("COGL_KMS_CONNECTOR%d_MODE", _index);
519   if (getenv (mode_env_name))
520     {
521       const char *name = getenv (mode_env_name);
522       int i;
523       CoglBool found = FALSE;
524       drmModeModeInfo mode;
525 
526       for (i = 0; i < n_modes; i++)
527         {
528           if (strcmp (modes[i].name, name) == 0)
529             {
530               found = TRUE;
531               break;
532             }
533         }
534       if (!found)
535         {
536           g_free (mode_env_name);
537           _cogl_set_error (error, COGL_WINSYS_ERROR,
538                        COGL_WINSYS_ERROR_INIT,
539                        "COGL_KMS_CONNECTOR%d_MODE of %s could not be found",
540                        _index, name);
541           return NULL;
542         }
543       n_modes = 1;
544       mode = modes[i];
545       g_free (modes);
546       modes = g_new (drmModeModeInfo, 1);
547       modes[0] = mode;
548     }
549   g_free (mode_env_name);
550 
551   output->modes = modes;
552   output->n_modes = n_modes;
553 
554   return output;
555 }
556 
557 static void
setup_crtc_modes(CoglDisplay * display,int fb_id)558 setup_crtc_modes (CoglDisplay *display, int fb_id)
559 {
560   CoglDisplayEGL *egl_display = display->winsys;
561   CoglDisplayKMS *kms_display = egl_display->platform;
562   CoglRendererEGL *egl_renderer = display->renderer->winsys;
563   CoglRendererKMS *kms_renderer = egl_renderer->platform;
564   GList *l;
565 
566   for (l = kms_display->crtcs; l; l = l->next)
567     {
568       CoglKmsCrtc *crtc = l->data;
569 
570       int ret = drmModeSetCrtc (kms_renderer->fd,
571                                 crtc->id,
572                                 fb_id, crtc->x, crtc->y,
573                                 crtc->connectors, crtc->count,
574                                 crtc->count ? &crtc->mode : NULL);
575       if (ret)
576         g_warning ("Failed to set crtc mode %s: %m", crtc->mode.name);
577     }
578 }
579 
580 static void
flip_all_crtcs(CoglDisplay * display,CoglFlipKMS * flip,int fb_id)581 flip_all_crtcs (CoglDisplay *display, CoglFlipKMS *flip, int fb_id)
582 {
583   CoglDisplayEGL *egl_display = display->winsys;
584   CoglDisplayKMS *kms_display = egl_display->platform;
585   CoglRendererEGL *egl_renderer = display->renderer->winsys;
586   CoglRendererKMS *kms_renderer = egl_renderer->platform;
587   GList *l;
588   gboolean needs_flip = FALSE;
589 
590   for (l = kms_display->crtcs; l; l = l->next)
591     {
592       CoglKmsCrtc *crtc = l->data;
593       int ret = 0;
594 
595       if (crtc->count == 0 || crtc->ignore)
596         continue;
597 
598       needs_flip = TRUE;
599 
600       if (!kms_renderer->page_flips_not_supported)
601         {
602           ret = drmModePageFlip (kms_renderer->fd,
603                                  crtc->id, fb_id,
604                                  DRM_MODE_PAGE_FLIP_EVENT, flip);
605           if (ret != 0 && ret != -EACCES)
606             {
607               g_warning ("Failed to flip: %m");
608               kms_renderer->page_flips_not_supported = TRUE;
609               break;
610             }
611         }
612 
613       if (ret == 0)
614         flip->pending++;
615     }
616 
617   if (kms_renderer->page_flips_not_supported && needs_flip)
618     flip->pending = 1;
619 }
620 
621 static void
crtc_free(CoglKmsCrtc * crtc)622 crtc_free (CoglKmsCrtc *crtc)
623 {
624   g_free (crtc->connectors);
625   g_slice_free (CoglKmsCrtc, crtc);
626 }
627 
628 static CoglKmsCrtc *
crtc_copy(CoglKmsCrtc * from)629 crtc_copy (CoglKmsCrtc *from)
630 {
631   CoglKmsCrtc *new;
632 
633   new = g_slice_new (CoglKmsCrtc);
634 
635   *new = *from;
636   new->connectors = g_memdup (from->connectors, from->count * sizeof(uint32_t));
637 
638   return new;
639 }
640 
641 static CoglBool
_cogl_winsys_egl_display_setup(CoglDisplay * display,CoglError ** error)642 _cogl_winsys_egl_display_setup (CoglDisplay *display,
643                                 CoglError **error)
644 {
645   CoglDisplayEGL *egl_display = display->winsys;
646   CoglDisplayKMS *kms_display;
647   CoglRendererEGL *egl_renderer = display->renderer->winsys;
648   CoglRendererKMS *kms_renderer = egl_renderer->platform;
649   drmModeRes *resources;
650   CoglOutputKMS *output0, *output1;
651   CoglBool mirror;
652   CoglKmsCrtc *crtc0, *crtc1;
653 
654   kms_display = g_slice_new0 (CoglDisplayKMS);
655   egl_display->platform = kms_display;
656 
657   resources = drmModeGetResources (kms_renderer->fd);
658   if (!resources)
659     {
660       _cogl_set_error (error, COGL_WINSYS_ERROR,
661                    COGL_WINSYS_ERROR_INIT,
662                    "drmModeGetResources failed");
663       return FALSE;
664     }
665 
666   /* Force a full modeset / drmModeSetCrtc on
667    * the first swap buffers call.
668    */
669   kms_display->pending_set_crtc = TRUE;
670 
671   if (kms_renderer->opened_fd < 0)
672     return TRUE;
673 
674   output0 = find_output (0,
675                          kms_renderer->fd,
676                          resources,
677                          NULL,
678                          0, /* n excluded connectors */
679                          error);
680   if (!output0)
681     return FALSE;
682 
683   kms_display->outputs = g_list_append (kms_display->outputs, output0);
684 
685   if (getenv ("COGL_KMS_MIRROR"))
686     mirror = TRUE;
687   else
688     mirror = FALSE;
689 
690   if (mirror)
691     {
692       int exclude_connector = output0->connector->connector_id;
693       output1 = find_output (1,
694                              kms_renderer->fd,
695                              resources,
696                              &exclude_connector,
697                              1, /* n excluded connectors */
698                              error);
699       if (!output1)
700         return FALSE;
701 
702       kms_display->outputs = g_list_append (kms_display->outputs, output1);
703 
704       if (!find_mirror_modes (output0->modes, output0->n_modes,
705                               output1->modes, output1->n_modes,
706                               &output0->mode,
707                               &output1->mode))
708         {
709           _cogl_set_error (error, COGL_WINSYS_ERROR,
710                        COGL_WINSYS_ERROR_INIT,
711                        "Failed to find matching modes for mirroring");
712           return FALSE;
713         }
714     }
715   else
716     {
717       output0->mode = output0->modes[0];
718       output1 = NULL;
719     }
720 
721   crtc0 = g_slice_new (CoglKmsCrtc);
722   crtc0->id = output0->encoder->crtc_id;
723   crtc0->x = 0;
724   crtc0->y = 0;
725   crtc0->mode = output0->mode;
726   crtc0->connectors = g_new (uint32_t, 1);
727   crtc0->connectors[0] = output0->connector->connector_id;
728   crtc0->count = 1;
729   kms_display->crtcs = g_list_prepend (kms_display->crtcs, crtc0);
730 
731   if (output1)
732     {
733       crtc1 = g_slice_new (CoglKmsCrtc);
734       crtc1->id = output1->encoder->crtc_id;
735       crtc1->x = 0;
736       crtc1->y = 0;
737       crtc1->mode = output1->mode;
738       crtc1->connectors = g_new (uint32_t, 1);
739       crtc1->connectors[0] = output1->connector->connector_id;
740       crtc1->count = 1;
741       kms_display->crtcs = g_list_prepend (kms_display->crtcs, crtc1);
742     }
743 
744   kms_display->width = output0->mode.hdisplay;
745   kms_display->height = output0->mode.vdisplay;
746 
747   return TRUE;
748 }
749 
750 static void
output_free(int fd,CoglOutputKMS * output)751 output_free (int fd, CoglOutputKMS *output)
752 {
753   if (output->modes)
754     g_free (output->modes);
755 
756   if (output->encoder)
757     drmModeFreeEncoder (output->encoder);
758 
759   if (output->connector)
760     {
761       if (output->saved_crtc)
762         {
763           int ret = drmModeSetCrtc (fd,
764                                     output->saved_crtc->crtc_id,
765                                     output->saved_crtc->buffer_id,
766                                     output->saved_crtc->x,
767                                     output->saved_crtc->y,
768                                     &output->connector->connector_id, 1,
769                                     &output->saved_crtc->mode);
770           if (ret)
771             g_warning (G_STRLOC ": Error restoring saved CRTC");
772         }
773       drmModeFreeConnector (output->connector);
774     }
775 
776   g_slice_free (CoglOutputKMS, output);
777 }
778 
779 static void
_cogl_winsys_egl_display_destroy(CoglDisplay * display)780 _cogl_winsys_egl_display_destroy (CoglDisplay *display)
781 {
782   CoglDisplayEGL *egl_display = display->winsys;
783   CoglDisplayKMS *kms_display = egl_display->platform;
784   CoglRenderer *renderer = display->renderer;
785   CoglRendererEGL *egl_renderer = renderer->winsys;
786   CoglRendererKMS *kms_renderer = egl_renderer->platform;
787   GList *l;
788 
789   for (l = kms_display->outputs; l; l = l->next)
790     output_free (kms_renderer->fd, l->data);
791   g_list_free (kms_display->outputs);
792   kms_display->outputs = NULL;
793 
794   g_list_free_full (kms_display->crtcs, (GDestroyNotify) crtc_free);
795 
796   g_slice_free (CoglDisplayKMS, egl_display->platform);
797 }
798 
799 static CoglBool
_cogl_winsys_egl_context_created(CoglDisplay * display,CoglError ** error)800 _cogl_winsys_egl_context_created (CoglDisplay *display,
801                                   CoglError **error)
802 {
803   CoglDisplayEGL *egl_display = display->winsys;
804   CoglDisplayKMS *kms_display = egl_display->platform;
805   CoglRenderer *renderer = display->renderer;
806   CoglRendererEGL *egl_renderer = renderer->winsys;
807   CoglRendererKMS *kms_renderer = egl_renderer->platform;
808 
809   if ((egl_renderer->private_features &
810        COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT) == 0)
811     {
812       kms_display->dummy_gbm_surface =
813         gbm_surface_create (kms_renderer->gbm,
814                             16, 16,
815                             GBM_FORMAT_XRGB8888,
816                             GBM_BO_USE_RENDERING);
817       if (!kms_display->dummy_gbm_surface)
818         {
819           _cogl_set_error (error, COGL_WINSYS_ERROR,
820                            COGL_WINSYS_ERROR_CREATE_CONTEXT,
821                            "Failed to create dummy GBM surface");
822           return FALSE;
823         }
824 
825       egl_display->dummy_surface =
826         eglCreateWindowSurface (egl_renderer->edpy,
827                                 egl_display->egl_config,
828                                 (EGLNativeWindowType)
829                                 kms_display->dummy_gbm_surface,
830                                 NULL);
831       if (egl_display->dummy_surface == EGL_NO_SURFACE)
832         {
833           _cogl_set_error (error, COGL_WINSYS_ERROR,
834                            COGL_WINSYS_ERROR_CREATE_CONTEXT,
835                            "Failed to create dummy EGL surface");
836           return FALSE;
837         }
838     }
839 
840   if (!_cogl_winsys_egl_make_current (display,
841                                       egl_display->dummy_surface,
842                                       egl_display->dummy_surface,
843                                       egl_display->egl_context))
844     {
845       _cogl_set_error (error, COGL_WINSYS_ERROR,
846                    COGL_WINSYS_ERROR_CREATE_CONTEXT,
847                    "Failed to make context current");
848       return FALSE;
849     }
850 
851   return TRUE;
852 }
853 
854 static void
_cogl_winsys_egl_cleanup_context(CoglDisplay * display)855 _cogl_winsys_egl_cleanup_context (CoglDisplay *display)
856 {
857   CoglDisplayEGL *egl_display = display->winsys;
858   CoglDisplayKMS *kms_display = egl_display->platform;
859   CoglRenderer *renderer = display->renderer;
860   CoglRendererEGL *egl_renderer = renderer->winsys;
861 
862   if (egl_display->dummy_surface != EGL_NO_SURFACE)
863     {
864       eglDestroySurface (egl_renderer->edpy, egl_display->dummy_surface);
865       egl_display->dummy_surface = EGL_NO_SURFACE;
866     }
867 
868   if (kms_display->dummy_gbm_surface != NULL)
869     {
870       gbm_surface_destroy (kms_display->dummy_gbm_surface);
871       kms_display->dummy_gbm_surface = NULL;
872     }
873 }
874 
875 static void
_cogl_winsys_onscreen_swap_buffers_with_damage(CoglOnscreen * onscreen,const int * rectangles,int n_rectangles)876 _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
877                                                 const int *rectangles,
878                                                 int n_rectangles)
879 {
880   CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
881   CoglDisplayEGL *egl_display = context->display->winsys;
882   CoglDisplayKMS *kms_display = egl_display->platform;
883   CoglRenderer *renderer = context->display->renderer;
884   CoglRendererEGL *egl_renderer = renderer->winsys;
885   CoglRendererKMS *kms_renderer = egl_renderer->platform;
886   CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
887   CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
888   uint32_t handle, stride;
889   CoglFlipKMS *flip;
890 
891   /* If we already have a pending swap then block until it completes */
892   while (kms_onscreen->next_fb_id != 0)
893     handle_drm_event (kms_renderer);
894 
895   if (kms_onscreen->pending_egl_surface)
896     {
897       eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface);
898       egl_onscreen->egl_surface = kms_onscreen->pending_egl_surface;
899       kms_onscreen->pending_egl_surface = NULL;
900 
901       _cogl_framebuffer_winsys_update_size (COGL_FRAMEBUFFER (kms_display->onscreen),
902                                             kms_display->width, kms_display->height);
903       context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND;
904     }
905   parent_vtable->onscreen_swap_buffers_with_damage (onscreen,
906                                                     rectangles,
907                                                     n_rectangles);
908 
909   if (kms_onscreen->pending_surface)
910     {
911       free_current_bo (onscreen);
912       if (kms_onscreen->surface)
913         gbm_surface_destroy (kms_onscreen->surface);
914       kms_onscreen->surface = kms_onscreen->pending_surface;
915       kms_onscreen->pending_surface = NULL;
916     }
917   /* Now we need to set the CRTC to whatever is the front buffer */
918   kms_onscreen->next_bo = gbm_surface_lock_front_buffer (kms_onscreen->surface);
919 
920 #if (COGL_VERSION_ENCODE (COGL_GBM_MAJOR, COGL_GBM_MINOR, COGL_GBM_MICRO) >= \
921      COGL_VERSION_ENCODE (8, 1, 0))
922   stride = gbm_bo_get_stride (kms_onscreen->next_bo);
923 #else
924   stride = gbm_bo_get_pitch (kms_onscreen->next_bo);
925 #endif
926   handle = gbm_bo_get_handle (kms_onscreen->next_bo).u32;
927 
928   if (drmModeAddFB (kms_renderer->fd,
929                     kms_display->width,
930                     kms_display->height,
931                     24, /* depth */
932                     32, /* bpp */
933                     stride,
934                     handle,
935                     &kms_onscreen->next_fb_id))
936     {
937       g_warning ("Failed to create new back buffer handle: %m");
938       gbm_surface_release_buffer (kms_onscreen->surface,
939                                   kms_onscreen->next_bo);
940       kms_onscreen->next_bo = NULL;
941       kms_onscreen->next_fb_id = 0;
942       return;
943     }
944 
945   /* If this is the first framebuffer to be presented then we now setup the
946    * crtc modes, else we flip from the previous buffer */
947   if (kms_display->pending_set_crtc)
948     {
949       setup_crtc_modes (context->display, kms_onscreen->next_fb_id);
950       kms_display->pending_set_crtc = FALSE;
951     }
952 
953   flip = g_slice_new0 (CoglFlipKMS);
954   flip->onscreen = onscreen;
955 
956   flip_all_crtcs (context->display, flip, kms_onscreen->next_fb_id);
957 
958   if (flip->pending == 0)
959     {
960       drmModeRmFB (kms_renderer->fd, kms_onscreen->next_fb_id);
961       gbm_surface_release_buffer (kms_onscreen->surface,
962                                   kms_onscreen->next_bo);
963       kms_onscreen->next_bo = NULL;
964       kms_onscreen->next_fb_id = 0;
965       g_slice_free (CoglFlipKMS, flip);
966       flip = NULL;
967 
968       queue_swap_notify_for_onscreen (onscreen);
969     }
970   else
971     {
972       /* Ensure the onscreen remains valid while it has any pending flips... */
973       cogl_object_ref (flip->onscreen);
974 
975       /* Process flip right away if we can't wait for vblank */
976       if (kms_renderer->page_flips_not_supported)
977         {
978           setup_crtc_modes (context->display, kms_onscreen->next_fb_id);
979           process_flip (flip);
980         }
981     }
982 }
983 
984 static CoglBool
_cogl_winsys_egl_context_init(CoglContext * context,CoglError ** error)985 _cogl_winsys_egl_context_init (CoglContext *context,
986                                CoglError **error)
987 {
988   COGL_FLAGS_SET (context->features,
989                   COGL_FEATURE_ID_SWAP_BUFFERS_EVENT, TRUE);
990   /* TODO: remove this deprecated feature */
991   COGL_FLAGS_SET (context->winsys_features,
992                   COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT,
993                   TRUE);
994   COGL_FLAGS_SET (context->winsys_features,
995                   COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT,
996                   TRUE);
997 
998   return TRUE;
999 }
1000 
1001 static CoglBool
_cogl_winsys_onscreen_init(CoglOnscreen * onscreen,CoglError ** error)1002 _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
1003                             CoglError **error)
1004 {
1005   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
1006   CoglContext *context = framebuffer->context;
1007   CoglDisplay *display = context->display;
1008   CoglDisplayEGL *egl_display = display->winsys;
1009   CoglDisplayKMS *kms_display = egl_display->platform;
1010   CoglRenderer *renderer = display->renderer;
1011   CoglRendererEGL *egl_renderer = renderer->winsys;
1012   CoglRendererKMS *kms_renderer = egl_renderer->platform;
1013   CoglOnscreenEGL *egl_onscreen;
1014   CoglOnscreenKMS *kms_onscreen;
1015 
1016   _COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context, FALSE);
1017 
1018   if (kms_display->onscreen)
1019     {
1020       _cogl_set_error (error, COGL_WINSYS_ERROR,
1021                        COGL_WINSYS_ERROR_CREATE_ONSCREEN,
1022                        "Cannot have multiple onscreens in the KMS platform");
1023       return FALSE;
1024     }
1025 
1026   kms_display->onscreen = onscreen;
1027 
1028   onscreen->winsys = g_slice_new0 (CoglOnscreenEGL);
1029   egl_onscreen = onscreen->winsys;
1030 
1031   kms_onscreen = g_slice_new0 (CoglOnscreenKMS);
1032   egl_onscreen->platform = kms_onscreen;
1033 
1034   /* If a kms_fd is set then the display width and height
1035    * won't be available until cogl_kms_display_set_layout
1036    * is called. In that case, defer creating the surface
1037    * until then.
1038    */
1039   if (kms_display->width == 0 ||
1040       kms_display->height == 0)
1041     return TRUE;
1042 
1043   kms_onscreen->surface =
1044     gbm_surface_create (kms_renderer->gbm,
1045                         kms_display->width,
1046                         kms_display->height,
1047                         GBM_FORMAT_XRGB8888,
1048                         GBM_BO_USE_SCANOUT |
1049                         GBM_BO_USE_RENDERING);
1050 
1051   if (!kms_onscreen->surface)
1052     {
1053       _cogl_set_error (error, COGL_WINSYS_ERROR,
1054                    COGL_WINSYS_ERROR_CREATE_ONSCREEN,
1055                    "Failed to allocate surface");
1056       return FALSE;
1057     }
1058 
1059   egl_onscreen->egl_surface =
1060     eglCreateWindowSurface (egl_renderer->edpy,
1061                             egl_display->egl_config,
1062                             (EGLNativeWindowType) kms_onscreen->surface,
1063                             NULL);
1064   if (egl_onscreen->egl_surface == EGL_NO_SURFACE)
1065     {
1066       _cogl_set_error (error, COGL_WINSYS_ERROR,
1067                    COGL_WINSYS_ERROR_CREATE_ONSCREEN,
1068                    "Failed to allocate surface");
1069       return FALSE;
1070     }
1071 
1072   _cogl_framebuffer_winsys_update_size (framebuffer,
1073                                         kms_display->width,
1074                                         kms_display->height);
1075 
1076   return TRUE;
1077 }
1078 
1079 static void
_cogl_winsys_onscreen_deinit(CoglOnscreen * onscreen)1080 _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
1081 {
1082   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
1083   CoglContext *context = framebuffer->context;
1084   CoglDisplay *display = context->display;
1085   CoglDisplayEGL *egl_display = display->winsys;
1086   CoglDisplayKMS *kms_display = egl_display->platform;
1087   CoglRenderer *renderer = context->display->renderer;
1088   CoglRendererEGL *egl_renderer = renderer->winsys;
1089   CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
1090   CoglOnscreenKMS *kms_onscreen;
1091 
1092   /* If we never successfully allocated then there's nothing to do */
1093   if (egl_onscreen == NULL)
1094     return;
1095 
1096   kms_display->onscreen = NULL;
1097 
1098   kms_onscreen = egl_onscreen->platform;
1099 
1100   /* flip state takes a reference on the onscreen so there should
1101    * never be outstanding flips when we reach here. */
1102   g_return_if_fail (kms_onscreen->next_fb_id == 0);
1103 
1104   free_current_bo (onscreen);
1105 
1106   if (egl_onscreen->egl_surface != EGL_NO_SURFACE)
1107     {
1108       eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface);
1109       egl_onscreen->egl_surface = EGL_NO_SURFACE;
1110     }
1111 
1112   if (kms_onscreen->surface)
1113     {
1114       gbm_surface_destroy (kms_onscreen->surface);
1115       kms_onscreen->surface = NULL;
1116     }
1117 
1118   g_slice_free (CoglOnscreenKMS, kms_onscreen);
1119   g_slice_free (CoglOnscreenEGL, onscreen->winsys);
1120   onscreen->winsys = NULL;
1121 }
1122 
1123 static const CoglWinsysEGLVtable
1124 _cogl_winsys_egl_vtable =
1125   {
1126     .display_setup = _cogl_winsys_egl_display_setup,
1127     .display_destroy = _cogl_winsys_egl_display_destroy,
1128     .context_created = _cogl_winsys_egl_context_created,
1129     .cleanup_context = _cogl_winsys_egl_cleanup_context,
1130     .context_init = _cogl_winsys_egl_context_init
1131   };
1132 
1133 const CoglWinsysVtable *
_cogl_winsys_egl_kms_get_vtable(void)1134 _cogl_winsys_egl_kms_get_vtable (void)
1135 {
1136   static CoglBool vtable_inited = FALSE;
1137   static CoglWinsysVtable vtable;
1138 
1139   if (!vtable_inited)
1140     {
1141       /* The EGL_KMS winsys is a subclass of the EGL winsys so we
1142          start by copying its vtable */
1143 
1144       parent_vtable = _cogl_winsys_egl_get_vtable ();
1145       vtable = *parent_vtable;
1146 
1147       vtable.id = COGL_WINSYS_ID_EGL_KMS;
1148       vtable.name = "EGL_KMS";
1149 
1150       vtable.renderer_connect = _cogl_winsys_renderer_connect;
1151       vtable.renderer_disconnect = _cogl_winsys_renderer_disconnect;
1152 
1153       vtable.onscreen_init = _cogl_winsys_onscreen_init;
1154       vtable.onscreen_deinit = _cogl_winsys_onscreen_deinit;
1155 
1156       /* The KMS winsys doesn't support swap region */
1157       vtable.onscreen_swap_region = NULL;
1158       vtable.onscreen_swap_buffers_with_damage =
1159         _cogl_winsys_onscreen_swap_buffers_with_damage;
1160 
1161       vtable_inited = TRUE;
1162     }
1163 
1164   return &vtable;
1165 }
1166 
1167 void
cogl_kms_renderer_set_kms_fd(CoglRenderer * renderer,int fd)1168 cogl_kms_renderer_set_kms_fd (CoglRenderer *renderer,
1169                               int fd)
1170 {
1171   _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer));
1172   /* NB: Renderers are considered immutable once connected */
1173   _COGL_RETURN_IF_FAIL (!renderer->connected);
1174 
1175   renderer->kms_fd = fd;
1176 }
1177 
1178 struct gbm_device *
cogl_kms_renderer_get_gbm(CoglRenderer * renderer)1179 cogl_kms_renderer_get_gbm (CoglRenderer *renderer)
1180 {
1181   _COGL_RETURN_VAL_IF_FAIL (cogl_is_renderer (renderer), NULL);
1182   if (renderer->connected)
1183     {
1184       CoglRendererEGL *egl_renderer = renderer->winsys;
1185       CoglRendererKMS *kms_renderer = egl_renderer->platform;
1186       return kms_renderer->gbm;
1187     }
1188     else
1189       return NULL;
1190 }
1191 
1192 int
cogl_kms_renderer_get_kms_fd(CoglRenderer * renderer)1193 cogl_kms_renderer_get_kms_fd (CoglRenderer *renderer)
1194 {
1195   _COGL_RETURN_VAL_IF_FAIL (cogl_is_renderer (renderer), -1);
1196 
1197   if (renderer->connected)
1198     {
1199       CoglRendererEGL *egl_renderer = renderer->winsys;
1200       CoglRendererKMS *kms_renderer = egl_renderer->platform;
1201       return kms_renderer->fd;
1202     }
1203   else
1204     return -1;
1205 }
1206 
1207 void
cogl_kms_display_queue_modes_reset(CoglDisplay * display)1208 cogl_kms_display_queue_modes_reset (CoglDisplay *display)
1209 {
1210   if (display->setup)
1211     {
1212       CoglDisplayEGL *egl_display = display->winsys;
1213       CoglDisplayKMS *kms_display = egl_display->platform;
1214       kms_display->pending_set_crtc = TRUE;
1215     }
1216 }
1217 
1218 CoglBool
cogl_kms_display_set_layout(CoglDisplay * display,int width,int height,CoglKmsCrtc ** crtcs,int n_crtcs,CoglError ** error)1219 cogl_kms_display_set_layout (CoglDisplay *display,
1220                              int width,
1221                              int height,
1222                              CoglKmsCrtc **crtcs,
1223                              int n_crtcs,
1224                              CoglError **error)
1225 {
1226   CoglDisplayEGL *egl_display = display->winsys;
1227   CoglDisplayKMS *kms_display = egl_display->platform;
1228   CoglRenderer *renderer = display->renderer;
1229   CoglRendererEGL *egl_renderer = renderer->winsys;
1230   CoglRendererKMS *kms_renderer = egl_renderer->platform;
1231   GList *crtc_list;
1232   int i;
1233 
1234   if ((width != kms_display->width ||
1235        height != kms_display->height) &&
1236       kms_display->onscreen)
1237     {
1238       CoglOnscreenEGL *egl_onscreen = kms_display->onscreen->winsys;
1239       CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
1240       struct gbm_surface *new_surface;
1241       EGLSurface new_egl_surface;
1242 
1243       /* Need to drop the GBM surface and create a new one */
1244 
1245       new_surface = gbm_surface_create (kms_renderer->gbm,
1246                                         width, height,
1247                                         GBM_FORMAT_XRGB8888,
1248                                         GBM_BO_USE_SCANOUT |
1249                                         GBM_BO_USE_RENDERING);
1250 
1251       if (!new_surface)
1252         {
1253           _cogl_set_error (error, COGL_WINSYS_ERROR,
1254                            COGL_WINSYS_ERROR_CREATE_ONSCREEN,
1255                            "Failed to allocate new surface");
1256           return FALSE;
1257         }
1258 
1259       new_egl_surface =
1260         eglCreateWindowSurface (egl_renderer->edpy,
1261                                 egl_display->egl_config,
1262                                 (EGLNativeWindowType) new_surface,
1263                                 NULL);
1264       if (new_egl_surface == EGL_NO_SURFACE)
1265         {
1266           _cogl_set_error (error, COGL_WINSYS_ERROR,
1267                            COGL_WINSYS_ERROR_CREATE_ONSCREEN,
1268                            "Failed to allocate new surface");
1269           gbm_surface_destroy (new_surface);
1270           return FALSE;
1271         }
1272 
1273       if (kms_onscreen->pending_egl_surface)
1274         eglDestroySurface (egl_renderer->edpy, kms_onscreen->pending_egl_surface);
1275       if (kms_onscreen->pending_surface)
1276         gbm_surface_destroy (kms_onscreen->pending_surface);
1277 
1278       /* If there's already a surface, wait until the next swap to switch
1279        * it out, otherwise, if we're just starting up we can use the new
1280        * surface right away.
1281        */
1282       if (kms_onscreen->surface != NULL)
1283         {
1284           kms_onscreen->pending_surface = new_surface;
1285           kms_onscreen->pending_egl_surface = new_egl_surface;
1286         }
1287       else
1288         {
1289           CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (kms_display->onscreen);
1290 
1291           kms_onscreen->surface = new_surface;
1292           egl_onscreen->egl_surface = new_egl_surface;
1293 
1294           _cogl_framebuffer_winsys_update_size (framebuffer, width, height);
1295         }
1296     }
1297 
1298   kms_display->width = width;
1299   kms_display->height = height;
1300 
1301   g_list_free_full (kms_display->crtcs, (GDestroyNotify) crtc_free);
1302 
1303   crtc_list = NULL;
1304   for (i = 0; i < n_crtcs; i++)
1305     {
1306       crtc_list = g_list_prepend (crtc_list, crtc_copy (crtcs[i]));
1307     }
1308   crtc_list = g_list_reverse (crtc_list);
1309   kms_display->crtcs = crtc_list;
1310 
1311   kms_display->pending_set_crtc = TRUE;
1312 
1313   return TRUE;
1314 }
1315 
1316 
1317 void
cogl_kms_display_set_ignore_crtc(CoglDisplay * display,uint32_t id,CoglBool ignore)1318 cogl_kms_display_set_ignore_crtc (CoglDisplay *display,
1319                                   uint32_t id,
1320                                   CoglBool ignore)
1321 {
1322   CoglDisplayEGL *egl_display = display->winsys;
1323   CoglDisplayKMS *kms_display = egl_display->platform;
1324   GList *l;
1325 
1326   for (l = kms_display->crtcs; l; l = l->next)
1327   {
1328     CoglKmsCrtc *crtc = l->data;
1329     if (crtc->id == id)
1330       {
1331         crtc->ignore = ignore;
1332         break;
1333       }
1334   }
1335 }
1336