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