compositor: Stop using EGL_KHR_surfaceless_gles2
[profile/ivi/weston.git] / src / compositor-drm.c
1 /*
2  * Copyright © 2008-2011 Kristian Høgsberg
3  * Copyright © 2011 Intel Corporation
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and
6  * its documentation for any purpose is hereby granted without fee, provided
7  * that the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation, and that the name of the copyright holders not be used in
10  * advertising or publicity pertaining to distribution of the software
11  * without specific, written prior permission.  The copyright holders make
12  * no representations about the suitability of this software for any
13  * purpose.  It is provided "as is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  */
23
24 #define _GNU_SOURCE
25
26 #include <errno.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32
33 #include <xf86drm.h>
34 #include <xf86drmMode.h>
35 #include <drm_fourcc.h>
36
37 #include <gbm.h>
38 #include <libbacklight.h>
39
40 #include "compositor.h"
41 #include "evdev.h"
42
43 struct drm_compositor {
44         struct weston_compositor base;
45
46         struct udev *udev;
47         struct wl_event_source *drm_source;
48
49         struct udev_monitor *udev_monitor;
50         struct wl_event_source *udev_drm_source;
51
52         struct {
53                 int id;
54                 int fd;
55         } drm;
56         struct gbm_device *gbm;
57         uint32_t *crtcs;
58         int num_crtcs;
59         uint32_t crtc_allocator;
60         uint32_t connector_allocator;
61         struct tty *tty;
62
63         struct gbm_surface *dummy_surface;
64         EGLSurface dummy_egl_surface;
65
66         struct wl_list sprite_list;
67         int sprites_are_broken;
68
69         uint32_t prev_state;
70 };
71
72 struct drm_mode {
73         struct weston_mode base;
74         drmModeModeInfo mode_info;
75 };
76
77 struct drm_output {
78         struct weston_output   base;
79
80         uint32_t crtc_id;
81         uint32_t connector_id;
82         drmModeCrtcPtr original_crtc;
83
84         struct gbm_surface *surface;
85         EGLSurface egl_surface;
86         uint32_t current_fb_id;
87         uint32_t next_fb_id;
88         struct gbm_bo *current_bo;
89         struct gbm_bo *next_bo;
90
91         struct wl_buffer *scanout_buffer;
92         struct wl_listener scanout_buffer_destroy_listener;
93         struct wl_buffer *pending_scanout_buffer;
94         struct wl_listener pending_scanout_buffer_destroy_listener;
95         struct backlight *backlight;
96 };
97
98 /*
99  * An output has a primary display plane plus zero or more sprites for
100  * blending display contents.
101  */
102 struct drm_sprite {
103         struct wl_list link;
104
105         uint32_t fb_id;
106         uint32_t pending_fb_id;
107         struct weston_surface *surface;
108         struct weston_surface *pending_surface;
109
110         struct drm_compositor *compositor;
111
112         struct wl_listener destroy_listener;
113         struct wl_listener pending_destroy_listener;
114
115         uint32_t possible_crtcs;
116         uint32_t plane_id;
117         uint32_t count_formats;
118
119         int32_t src_x, src_y;
120         uint32_t src_w, src_h;
121         uint32_t dest_x, dest_y;
122         uint32_t dest_w, dest_h;
123
124         uint32_t formats[];
125 };
126
127 static int
128 surface_is_primary(struct weston_compositor *ec, struct weston_surface *es)
129 {
130         struct weston_surface *primary;
131
132         primary = container_of(ec->surface_list.next, struct weston_surface,
133                                link);
134         if (es == primary)
135                 return -1;
136         return 0;
137 }
138
139 static int
140 drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
141 {
142         struct weston_compositor *ec = output_base->compositor;
143         struct drm_compositor *c =(struct drm_compositor *) ec;
144         struct drm_output *output = (struct drm_output *) output_base;
145         int crtc;
146
147         for (crtc = 0; crtc < c->num_crtcs; crtc++) {
148                 if (c->crtcs[crtc] != output->crtc_id)
149                         continue;
150
151                 if (supported & (1 << crtc))
152                         return -1;
153         }
154
155         return 0;
156 }
157
158 static int
159 drm_output_prepare_scanout_surface(struct drm_output *output)
160 {
161         struct drm_compositor *c =
162                 (struct drm_compositor *) output->base.compositor;
163         struct weston_surface *es;
164
165         es = container_of(c->base.surface_list.next,
166                           struct weston_surface, link);
167
168         /* Need to verify output->region contained in surface opaque
169          * region.  Or maybe just that format doesn't have alpha. */
170         return -1;
171
172         if (es->geometry.x != output->base.x ||
173             es->geometry.y != output->base.y ||
174             es->geometry.width != output->base.current->width ||
175             es->geometry.height != output->base.current->height ||
176             es->transform.enabled ||
177             es->image == EGL_NO_IMAGE_KHR)
178                 return -1;
179
180         output->next_bo =
181                 gbm_bo_create_from_egl_image(c->gbm,
182                                              c->base.display, es->image,
183                                              es->geometry.width,
184                                              es->geometry.height,
185                                              GBM_BO_USE_SCANOUT);
186
187         /* assert output->pending_scanout_buffer == NULL */
188         output->pending_scanout_buffer = es->buffer;
189         output->pending_scanout_buffer->busy_count++;
190
191         wl_list_insert(output->pending_scanout_buffer->resource.destroy_listener_list.prev,
192                        &output->pending_scanout_buffer_destroy_listener.link);
193
194         pixman_region32_fini(&es->damage);
195         pixman_region32_init(&es->damage);
196
197         return 0;
198 }
199
200 static void
201 drm_output_render(struct drm_output *output, pixman_region32_t *damage)
202 {
203         struct drm_compositor *compositor =
204                 (struct drm_compositor *) output->base.compositor;
205         struct weston_surface *surface;
206
207         if (!eglMakeCurrent(compositor->base.display, output->egl_surface,
208                             output->egl_surface, compositor->base.context)) {
209                 fprintf(stderr, "failed to make current\n");
210                 return;
211         }
212
213         wl_list_for_each_reverse(surface, &compositor->base.surface_list, link)
214                 weston_surface_draw(surface, &output->base, damage);
215
216         eglSwapBuffers(compositor->base.display, output->egl_surface);
217         output->next_bo = gbm_surface_lock_front_buffer(output->surface);
218         if (!output->next_bo) {
219                 fprintf(stderr, "failed to lock front buffer: %m\n");
220                 return;
221         }
222 }
223
224 static void
225 drm_output_repaint(struct weston_output *output_base,
226                    pixman_region32_t *damage)
227 {
228         struct drm_output *output = (struct drm_output *) output_base;
229         struct drm_compositor *compositor =
230                 (struct drm_compositor *) output->base.compositor;
231         struct drm_sprite *s;
232         struct drm_mode *mode;
233         uint32_t stride, handle;
234         int ret = 0;
235
236         drm_output_prepare_scanout_surface(output);
237         if (!output->next_bo)
238                 drm_output_render(output, damage);
239
240         stride = gbm_bo_get_pitch(output->next_bo);
241         handle = gbm_bo_get_handle(output->next_bo).u32;
242
243         /* Destroy and set to NULL now so we don't try to
244          * gbm_surface_release_buffer() a client buffer in the
245          * page_flip_handler. */
246         if (output->pending_scanout_buffer) {
247                 gbm_bo_destroy(output->next_bo);
248                 output->next_bo = NULL;
249         }
250
251         ret = drmModeAddFB(compositor->drm.fd,
252                            output->base.current->width,
253                            output->base.current->height,
254                            24, 32, stride, handle, &output->next_fb_id);
255         if (ret) {
256                 fprintf(stderr, "failed to create kms fb: %m\n");
257                 gbm_surface_release_buffer(output->surface, output->next_bo);
258                 output->next_bo = NULL;
259                 return;
260         }
261
262         mode = container_of(output->base.current, struct drm_mode, base);
263         if (output->current_fb_id == 0) {
264                 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
265                                      output->next_fb_id, 0, 0,
266                                      &output->connector_id, 1,
267                                      &mode->mode_info);
268                 if (ret) {
269                         fprintf(stderr, "set mode failed: %m\n");
270                         return;
271                 }
272         }
273
274         if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
275                             output->next_fb_id,
276                             DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
277                 fprintf(stderr, "queueing pageflip failed: %m\n");
278                 return;
279         }
280
281         /*
282          * Now, update all the sprite surfaces
283          */
284         wl_list_for_each(s, &compositor->sprite_list, link) {
285                 uint32_t flags = 0;
286                 drmVBlank vbl = {
287                         .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
288                         .request.sequence = 1,
289                 };
290
291                 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
292                         continue;
293
294                 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
295                                       output->crtc_id, s->pending_fb_id, flags,
296                                       s->dest_x, s->dest_y,
297                                       s->dest_w, s->dest_h,
298                                       s->src_x, s->src_y,
299                                       s->src_w, s->src_h);
300                 if (ret)
301                         fprintf(stderr, "setplane failed: %d: %s\n",
302                                 ret, strerror(errno));
303
304                 /*
305                  * Queue a vblank signal so we know when the surface
306                  * becomes active on the display or has been replaced.
307                  */
308                 vbl.request.signal = (unsigned long)s;
309                 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
310                 if (ret) {
311                         fprintf(stderr, "vblank event request failed: %d: %s\n",
312                                 ret, strerror(errno));
313                 }
314         }
315
316         return;
317 }
318
319 static void
320 vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
321                void *data)
322 {
323         struct drm_sprite *s = (struct drm_sprite *)data;
324         struct drm_compositor *c = s->compositor;
325
326         if (s->surface) {
327                 weston_buffer_post_release(s->surface->buffer);
328                 wl_list_remove(&s->destroy_listener.link);
329                 s->surface = NULL;
330                 drmModeRmFB(c->drm.fd, s->fb_id);
331                 s->fb_id = 0;
332         }
333
334         if (s->pending_surface) {
335                 wl_list_remove(&s->pending_destroy_listener.link);
336                 wl_list_insert(s->pending_surface->buffer->resource.destroy_listener_list.prev,
337                                &s->destroy_listener.link);
338                 s->surface = s->pending_surface;
339                 s->pending_surface = NULL;
340                 s->fb_id = s->pending_fb_id;
341                 s->pending_fb_id = 0;
342         }
343 }
344
345 static void
346 page_flip_handler(int fd, unsigned int frame,
347                   unsigned int sec, unsigned int usec, void *data)
348 {
349         struct drm_output *output = (struct drm_output *) data;
350         struct drm_compositor *c =
351                 (struct drm_compositor *) output->base.compositor;
352         uint32_t msecs;
353
354         if (output->current_fb_id)
355                 drmModeRmFB(c->drm.fd, output->current_fb_id);
356         output->current_fb_id = output->next_fb_id;
357         output->next_fb_id = 0;
358
359         if (output->scanout_buffer) {
360                 weston_buffer_post_release(output->scanout_buffer);
361                 wl_list_remove(&output->scanout_buffer_destroy_listener.link);
362                 output->scanout_buffer = NULL;
363         } else if (output->current_bo) {
364                 gbm_surface_release_buffer(output->surface,
365                                            output->current_bo);
366         }
367
368         output->current_bo = output->next_bo;
369         output->next_bo = NULL;
370
371         if (output->pending_scanout_buffer) {
372                 output->scanout_buffer = output->pending_scanout_buffer;
373                 wl_list_remove(&output->pending_scanout_buffer_destroy_listener.link);
374                 wl_list_insert(output->scanout_buffer->resource.destroy_listener_list.prev,
375                                &output->scanout_buffer_destroy_listener.link);
376                 output->pending_scanout_buffer = NULL;
377         }
378         msecs = sec * 1000 + usec / 1000;
379         weston_output_finish_frame(&output->base, msecs);
380 }
381
382 static int
383 drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
384 {
385         int i;
386
387         for (i = 0; i < s->count_formats; i++)
388                 if (s->formats[i] == format)
389                         return 1;
390
391         return 0;
392 }
393
394 static int
395 drm_surface_transform_supported(struct weston_surface *es)
396 {
397         if (es->transform.enabled)
398                 return 0;
399
400         return 1;
401 }
402
403 static int
404 drm_surface_overlap_supported(struct weston_output *output_base,
405                               pixman_region32_t *overlap)
406 {
407         /* We could potentially use a color key here if the surface left
408          * to display has rectangular regions
409          */
410         if (pixman_region32_not_empty(overlap))
411                 return 0;
412         return 1;
413 }
414
415 static void
416 drm_disable_unused_sprites(struct weston_output *output_base)
417 {
418         struct weston_compositor *ec = output_base->compositor;
419         struct drm_compositor *c =(struct drm_compositor *) ec;
420         struct drm_output *output = (struct drm_output *) output_base;
421         struct drm_sprite *s;
422         int ret;
423
424         wl_list_for_each(s, &c->sprite_list, link) {
425                 if (s->pending_fb_id)
426                         continue;
427
428                 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
429                                       output->crtc_id, 0, 0,
430                                       0, 0, 0, 0, 0, 0, 0, 0);
431                 if (ret)
432                         fprintf(stderr,
433                                 "failed to disable plane: %d: %s\n",
434                                 ret, strerror(errno));
435                 drmModeRmFB(c->drm.fd, s->fb_id);
436                 s->surface = NULL;
437                 s->pending_surface = NULL;
438                 s->fb_id = 0;
439                 s->pending_fb_id = 0;
440         }
441 }
442
443 /*
444  * This function must take care to damage any previously assigned surface
445  * if the sprite ends up binding to a different surface than in the
446  * previous frame.
447  */
448 static int
449 drm_output_prepare_overlay_surface(struct weston_output *output_base,
450                                    struct weston_surface *es,
451                                    pixman_region32_t *overlap)
452 {
453         struct weston_compositor *ec = output_base->compositor;
454         struct drm_compositor *c =(struct drm_compositor *) ec;
455         struct drm_sprite *s;
456         int found = 0;
457         EGLint handle, stride;
458         struct gbm_bo *bo;
459         uint32_t fb_id = 0;
460         uint32_t handles[4], pitches[4], offsets[4];
461         int ret = 0;
462         pixman_region32_t dest_rect, src_rect;
463         pixman_box32_t *box;
464         uint32_t format;
465
466         if (c->sprites_are_broken)
467                 return -1;
468
469         if (surface_is_primary(ec, es))
470                 return -1;
471
472         if (es->image == EGL_NO_IMAGE_KHR)
473                 return -1;
474
475         if (!drm_surface_transform_supported(es))
476                 return -1;
477
478         if (!drm_surface_overlap_supported(output_base, overlap))
479                 return -1;
480
481         wl_list_for_each(s, &c->sprite_list, link) {
482                 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
483                         continue;
484
485                 if (!s->pending_fb_id) {
486                         found = 1;
487                         break;
488                 }
489         }
490
491         /* No sprites available */
492         if (!found)
493                 return -1;
494
495         bo = gbm_bo_create_from_egl_image(c->gbm, c->base.display, es->image,
496                                           es->geometry.width, es->geometry.height,
497                                           GBM_BO_USE_SCANOUT);
498         format = gbm_bo_get_format(bo);
499         handle = gbm_bo_get_handle(bo).s32;
500         stride = gbm_bo_get_pitch(bo);
501
502         gbm_bo_destroy(bo);
503
504         if (!drm_surface_format_supported(s, format))
505                 return -1;
506
507         if (!handle)
508                 return -1;
509
510         handles[0] = handle;
511         pitches[0] = stride;
512         offsets[0] = 0;
513
514         ret = drmModeAddFB2(c->drm.fd, es->geometry.width, es->geometry.height,
515                             format, handles, pitches, offsets,
516                             &fb_id, 0);
517         if (ret) {
518                 fprintf(stderr, "addfb2 failed: %d\n", ret);
519                 c->sprites_are_broken = 1;
520                 return -1;
521         }
522
523         if (s->surface && s->surface != es) {
524                 struct weston_surface *old_surf = s->surface;
525                 pixman_region32_fini(&old_surf->damage);
526                 pixman_region32_init_rect(&old_surf->damage,
527                                           old_surf->geometry.x, old_surf->geometry.y,
528                                           old_surf->geometry.width, old_surf->geometry.height);
529         }
530
531         s->pending_fb_id = fb_id;
532         s->pending_surface = es;
533         es->buffer->busy_count++;
534
535         /*
536          * Calculate the source & dest rects properly based on actual
537          * postion (note the caller has called weston_surface_update_transform()
538          * for us already).
539          */
540         pixman_region32_init(&dest_rect);
541         pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
542                                   &output_base->region);
543         pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
544         box = pixman_region32_extents(&dest_rect);
545         s->dest_x = box->x1;
546         s->dest_y = box->y1;
547         s->dest_w = box->x2 - box->x1;
548         s->dest_h = box->y2 - box->y1;
549         pixman_region32_fini(&dest_rect);
550
551         pixman_region32_init(&src_rect);
552         pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
553                                   &output_base->region);
554         pixman_region32_translate(&src_rect, -es->geometry.x, -es->geometry.y);
555         box = pixman_region32_extents(&src_rect);
556         s->src_x = box->x1 << 16;
557         s->src_y = box->y1 << 16;
558         s->src_w = (box->x2 - box->x1) << 16;
559         s->src_h = (box->y2 - box->y1) << 16;
560         pixman_region32_fini(&src_rect);
561
562         wl_list_insert(es->buffer->resource.destroy_listener_list.prev,
563                        &s->pending_destroy_listener.link);
564         return 0;
565 }
566
567 static int
568 drm_output_set_cursor(struct weston_output *output_base,
569                       struct weston_input_device *eid);
570
571 static void
572 weston_output_set_cursor(struct weston_output *output,
573                          struct weston_input_device *device,
574                          pixman_region32_t *overlap)
575 {
576         pixman_region32_t cursor_region;
577         int prior_was_hardware;
578
579         if (device->sprite == NULL)
580                 return;
581
582         pixman_region32_init(&cursor_region);
583         pixman_region32_intersect(&cursor_region,
584                                   &device->sprite->transform.boundingbox,
585                                   &output->region);
586
587         if (!pixman_region32_not_empty(&cursor_region)) {
588                 drm_output_set_cursor(output, NULL);
589                 goto out;
590         }
591
592         prior_was_hardware = device->hw_cursor;
593         if (pixman_region32_not_empty(overlap) ||
594             drm_output_set_cursor(output, device) < 0) {
595                 if (prior_was_hardware) {
596                         weston_surface_damage(device->sprite);
597                         drm_output_set_cursor(output, NULL);
598                 }
599                 device->hw_cursor = 0;
600         } else {
601                 if (!prior_was_hardware)
602                         weston_surface_damage_below(device->sprite);
603                 pixman_region32_fini(&device->sprite->damage);
604                 pixman_region32_init(&device->sprite->damage);
605                 device->hw_cursor = 1;
606         }
607
608 out:
609         pixman_region32_fini(&cursor_region);
610 }
611
612 static void
613 drm_assign_planes(struct weston_output *output)
614 {
615         struct weston_compositor *ec = output->compositor;
616         struct weston_surface *es;
617         pixman_region32_t overlap, surface_overlap;
618         struct weston_input_device *device;
619
620         /*
621          * Find a surface for each sprite in the output using some heuristics:
622          * 1) size
623          * 2) frequency of update
624          * 3) opacity (though some hw might support alpha blending)
625          * 4) clipping (this can be fixed with color keys)
626          *
627          * The idea is to save on blitting since this should save power.
628          * If we can get a large video surface on the sprite for example,
629          * the main display surface may not need to update at all, and
630          * the client buffer can be used directly for the sprite surface
631          * as we do for flipping full screen surfaces.
632          */
633         pixman_region32_init(&overlap);
634         wl_list_for_each(es, &ec->surface_list, link) {
635                 /*
636                  * FIXME: try to assign hw cursors here too, they're just
637                  * special overlays
638                  */
639                 pixman_region32_init(&surface_overlap);
640                 pixman_region32_intersect(&surface_overlap, &overlap,
641                                           &es->transform.boundingbox);
642
643                 device = (struct weston_input_device *) ec->input_device;
644                 if (es == device->sprite) {
645                         weston_output_set_cursor(output, device,
646                                                  &surface_overlap);
647
648                         if (!device->hw_cursor)
649                                 pixman_region32_union(&overlap, &overlap,
650                                                       &es->transform.boundingbox);
651                 } else if (!drm_output_prepare_overlay_surface(output, es,
652                                                                &surface_overlap)) {
653                         pixman_region32_fini(&es->damage);
654                         pixman_region32_init(&es->damage);
655                 } else {
656                         pixman_region32_union(&overlap, &overlap,
657                                               &es->transform.boundingbox);
658                 }
659                 pixman_region32_fini(&surface_overlap);
660         }
661         pixman_region32_fini(&overlap);
662
663         drm_disable_unused_sprites(output);
664 }
665
666 static int
667 drm_output_set_cursor(struct weston_output *output_base,
668                       struct weston_input_device *eid)
669 {
670         struct drm_output *output = (struct drm_output *) output_base;
671         struct drm_compositor *c =
672                 (struct drm_compositor *) output->base.compositor;
673         EGLint handle, stride;
674         int ret = -1;
675         struct gbm_bo *bo;
676
677         if (eid == NULL) {
678                 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
679                 return 0;
680         }
681
682         if (eid->sprite->image == EGL_NO_IMAGE_KHR)
683                 goto out;
684
685         if (eid->sprite->geometry.width > 64 ||
686             eid->sprite->geometry.height > 64)
687                 goto out;
688
689         bo = gbm_bo_create_from_egl_image(c->gbm,
690                                           c->base.display,
691                                           eid->sprite->image, 64, 64,
692                                           GBM_BO_USE_CURSOR_64X64);
693         /* Not suitable for hw cursor, fall back */
694         if (bo == NULL)
695                 goto out;
696
697         handle = gbm_bo_get_handle(bo).s32;
698         stride = gbm_bo_get_pitch(bo);
699         gbm_bo_destroy(bo);
700
701         /* gbm_bo_create_from_egl_image() didn't always validate the usage
702          * flags, and in that case we might end up with a bad stride. */
703         if (stride != 64 * 4)
704                 goto out;
705
706         ret = drmModeSetCursor(c->drm.fd, output->crtc_id, handle, 64, 64);
707         if (ret) {
708                 fprintf(stderr, "failed to set cursor: %s\n", strerror(-ret));
709                 goto out;
710         }
711
712         ret = drmModeMoveCursor(c->drm.fd, output->crtc_id,
713                                 eid->sprite->geometry.x - output->base.x,
714                                 eid->sprite->geometry.y - output->base.y);
715         if (ret) {
716                 fprintf(stderr, "failed to move cursor: %s\n", strerror(-ret));
717                 goto out;
718         }
719
720 out:
721         if (ret)
722                 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
723         return ret;
724 }
725
726 static void
727 drm_output_destroy(struct weston_output *output_base)
728 {
729         struct drm_output *output = (struct drm_output *) output_base;
730         struct drm_compositor *c =
731                 (struct drm_compositor *) output->base.compositor;
732         drmModeCrtcPtr origcrtc = output->original_crtc;
733
734         if (output->backlight)
735                 backlight_destroy(output->backlight);
736
737         /* Turn off hardware cursor */
738         drm_output_set_cursor(&output->base, NULL);
739
740         /* Restore original CRTC state */
741         drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
742                        origcrtc->x, origcrtc->y,
743                        &output->connector_id, 1, &origcrtc->mode);
744         drmModeFreeCrtc(origcrtc);
745
746         c->crtc_allocator &= ~(1 << output->crtc_id);
747         c->connector_allocator &= ~(1 << output->connector_id);
748
749         eglDestroySurface(c->base.display, output->egl_surface);
750         gbm_surface_destroy(output->surface);
751
752         weston_output_destroy(&output->base);
753         wl_list_remove(&output->base.link);
754
755         free(output);
756 }
757
758 static int
759 on_drm_input(int fd, uint32_t mask, void *data)
760 {
761         drmEventContext evctx;
762
763         memset(&evctx, 0, sizeof evctx);
764         evctx.version = DRM_EVENT_CONTEXT_VERSION;
765         evctx.page_flip_handler = page_flip_handler;
766         evctx.vblank_handler = vblank_handler;
767         drmHandleEvent(fd, &evctx);
768
769         return 1;
770 }
771
772 static int
773 init_egl(struct drm_compositor *ec, struct udev_device *device)
774 {
775         EGLint major, minor, n;
776         const char *filename, *sysnum;
777         int fd;
778         static const EGLint context_attribs[] = {
779                 EGL_CONTEXT_CLIENT_VERSION, 2,
780                 EGL_NONE
781         };
782
783         sysnum = udev_device_get_sysnum(device);
784         if (sysnum)
785                 ec->drm.id = atoi(sysnum);
786         if (!sysnum || ec->drm.id < 0) {
787                 fprintf(stderr, "cannot get device sysnum\n");
788                 return -1;
789         }
790
791         static const EGLint config_attribs[] = {
792                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
793                 EGL_RED_SIZE, 1,
794                 EGL_GREEN_SIZE, 1,
795                 EGL_BLUE_SIZE, 1,
796                 EGL_ALPHA_SIZE, 0,
797                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
798                 EGL_NONE
799         };
800
801         filename = udev_device_get_devnode(device);
802         fd = open(filename, O_RDWR | O_CLOEXEC);
803         if (fd < 0) {
804                 /* Probably permissions error */
805                 fprintf(stderr, "couldn't open %s, skipping\n",
806                         udev_device_get_devnode(device));
807                 return -1;
808         }
809
810         ec->drm.fd = fd;
811         ec->gbm = gbm_create_device(ec->drm.fd);
812         ec->base.display = eglGetDisplay(ec->gbm);
813         if (ec->base.display == NULL) {
814                 fprintf(stderr, "failed to create display\n");
815                 return -1;
816         }
817
818         if (!eglInitialize(ec->base.display, &major, &minor)) {
819                 fprintf(stderr, "failed to initialize display\n");
820                 return -1;
821         }
822
823         if (!eglBindAPI(EGL_OPENGL_ES_API)) {
824                 fprintf(stderr, "failed to bind api EGL_OPENGL_ES_API\n");
825                 return -1;
826         }
827
828         if (!eglChooseConfig(ec->base.display, config_attribs,
829                              &ec->base.config, 1, &n) || n != 1) {
830                 fprintf(stderr, "failed to choose config: %d\n", n);
831                 return -1;
832         }
833
834         ec->base.context = eglCreateContext(ec->base.display, ec->base.config,
835                                             EGL_NO_CONTEXT, context_attribs);
836         if (ec->base.context == NULL) {
837                 fprintf(stderr, "failed to create context\n");
838                 return -1;
839         }
840
841         ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
842                                                GBM_FORMAT_XRGB8888,
843                                                GBM_BO_USE_RENDERING);
844         if (!ec->dummy_surface) {
845                 fprintf(stderr, "failed to create dummy gbm surface\n");
846                 return -1;
847         }
848
849         ec->dummy_egl_surface =
850                 eglCreateWindowSurface(ec->base.display, ec->base.config,
851                                        ec->dummy_surface, NULL);
852         if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
853                 fprintf(stderr, "failed to create egl surface\n");
854                 return -1;
855         }
856
857         if (!eglMakeCurrent(ec->base.display, ec->dummy_egl_surface,
858                             ec->dummy_egl_surface, ec->base.context)) {
859                 fprintf(stderr, "failed to make context current\n");
860                 return -1;
861         }
862
863         return 0;
864 }
865
866 static drmModeModeInfo builtin_1024x768 = {
867         63500,                  /* clock */
868         1024, 1072, 1176, 1328, 0,
869         768, 771, 775, 798, 0,
870         59920,
871         DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC,
872         0,
873         "1024x768"
874 };
875
876
877 static int
878 drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
879 {
880         struct drm_mode *mode;
881
882         mode = malloc(sizeof *mode);
883         if (mode == NULL)
884                 return -1;
885
886         mode->base.flags = 0;
887         mode->base.width = info->hdisplay;
888         mode->base.height = info->vdisplay;
889         mode->base.refresh = info->vrefresh;
890         mode->mode_info = *info;
891         wl_list_insert(output->base.mode_list.prev, &mode->base.link);
892
893         return 0;
894 }
895
896 static int
897 drm_subpixel_to_wayland(int drm_value)
898 {
899         switch (drm_value) {
900         default:
901         case DRM_MODE_SUBPIXEL_UNKNOWN:
902                 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
903         case DRM_MODE_SUBPIXEL_NONE:
904                 return WL_OUTPUT_SUBPIXEL_NONE;
905         case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
906                 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
907         case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
908                 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
909         case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
910                 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
911         case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
912                 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
913         }
914 }
915
916 static void
917 output_handle_scanout_buffer_destroy(struct wl_listener *listener,
918                                      struct wl_resource *resource,
919                                      uint32_t time)
920 {
921         struct drm_output *output =
922                 container_of(listener, struct drm_output,
923                              scanout_buffer_destroy_listener);
924
925         output->scanout_buffer = NULL;
926
927         if (!output->pending_scanout_buffer)
928                 weston_compositor_schedule_repaint(output->base.compositor);
929 }
930
931 static void
932 output_handle_pending_scanout_buffer_destroy(struct wl_listener *listener,
933                                              struct wl_resource *resource,
934                                              uint32_t time)
935 {
936         struct drm_output *output =
937                 container_of(listener, struct drm_output,
938                              pending_scanout_buffer_destroy_listener);
939
940         output->pending_scanout_buffer = NULL;
941
942         weston_compositor_schedule_repaint(output->base.compositor);
943 }
944
945 static void
946 sprite_handle_buffer_destroy(struct wl_listener *listener,
947                              struct wl_resource *resource,
948                              uint32_t time)
949 {
950         struct drm_sprite *sprite =
951                 container_of(listener, struct drm_sprite,
952                              destroy_listener);
953
954         sprite->surface = NULL;
955 }
956
957 static void
958 sprite_handle_pending_buffer_destroy(struct wl_listener *listener,
959                                      struct wl_resource *resource,
960                                      uint32_t time)
961 {
962         struct drm_sprite *sprite =
963                 container_of(listener, struct drm_sprite,
964                              pending_destroy_listener);
965
966         sprite->pending_surface = NULL;
967 }
968
969 /* returns a value between 0-255 range, where higher is brighter */
970 static uint32_t
971 drm_get_backlight(struct drm_output *output)
972 {
973         long brightness, max_brightness, norm;
974
975         brightness = backlight_get_brightness(output->backlight);
976         max_brightness = backlight_get_max_brightness(output->backlight);
977
978         /* convert it on a scale of 0 to 255 */
979         norm = (brightness * 255)/(max_brightness);
980
981         return (uint32_t) norm;
982 }
983
984 /* values accepted are between 0-255 range */
985 static void
986 drm_set_backlight(struct weston_output *output_base, uint32_t value)
987 {
988         struct drm_output *output = (struct drm_output *) output_base;
989         long max_brightness, new_brightness;
990
991         if (!output->backlight)
992                 return;
993
994         if (value < 0 || value > 255)
995                 return;
996
997         max_brightness = backlight_get_max_brightness(output->backlight);
998
999         /* get denormalized value */
1000         new_brightness = (value * max_brightness) / 255;
1001
1002         backlight_set_brightness(output->backlight, new_brightness);
1003 }
1004
1005 static drmModePropertyPtr
1006 drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1007 {
1008         drmModePropertyPtr props;
1009         int i;
1010
1011         for (i = 0; i < connector->count_props; i++) {
1012                 props = drmModeGetProperty(fd, connector->props[i]);
1013                 if (!props)
1014                         continue;
1015
1016                 if (!strcmp(props->name, name))
1017                         return props;
1018
1019                 drmModeFreeProperty(props);
1020         }
1021
1022         return NULL;
1023 }
1024
1025 static void
1026 drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1027 {
1028         struct drm_output *output = (struct drm_output *) output_base;
1029         struct weston_compositor *ec = output_base->compositor;
1030         struct drm_compositor *c = (struct drm_compositor *) ec;
1031         drmModeConnectorPtr connector;
1032         drmModePropertyPtr prop;
1033
1034         connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1035         if (!connector)
1036                 return;
1037
1038         prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1039         if (!prop) {
1040                 drmModeFreeConnector(connector);
1041                 return;
1042         }
1043
1044         drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1045                                     prop->prop_id, level);
1046         drmModeFreeProperty(prop);
1047         drmModeFreeConnector(connector);
1048 }
1049
1050 static int
1051 create_output_for_connector(struct drm_compositor *ec,
1052                             drmModeRes *resources,
1053                             drmModeConnector *connector,
1054                             int x, int y, struct udev_device *drm_device)
1055 {
1056         struct drm_output *output;
1057         struct drm_mode *drm_mode, *next;
1058         drmModeEncoder *encoder;
1059         int i, ret;
1060
1061         encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[0]);
1062         if (encoder == NULL) {
1063                 fprintf(stderr, "No encoder for connector.\n");
1064                 return -1;
1065         }
1066
1067         for (i = 0; i < resources->count_crtcs; i++) {
1068                 if (encoder->possible_crtcs & (1 << i) &&
1069                     !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1070                         break;
1071         }
1072         if (i == resources->count_crtcs) {
1073                 fprintf(stderr, "No usable crtc for encoder.\n");
1074                 drmModeFreeEncoder(encoder);
1075                 return -1;
1076         }
1077
1078         output = malloc(sizeof *output);
1079         if (output == NULL) {
1080                 drmModeFreeEncoder(encoder);
1081                 return -1;
1082         }
1083
1084         memset(output, 0, sizeof *output);
1085         output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1086         output->base.make = "unknown";
1087         output->base.model = "unknown";
1088         wl_list_init(&output->base.mode_list);
1089
1090         output->crtc_id = resources->crtcs[i];
1091         ec->crtc_allocator |= (1 << output->crtc_id);
1092         output->connector_id = connector->connector_id;
1093         ec->connector_allocator |= (1 << output->connector_id);
1094
1095         output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1096         drmModeFreeEncoder(encoder);
1097
1098         for (i = 0; i < connector->count_modes; i++) {
1099                 ret = drm_output_add_mode(output, &connector->modes[i]);
1100                 if (ret)
1101                         goto err_free;
1102         }
1103
1104         if (connector->count_modes == 0) {
1105                 ret = drm_output_add_mode(output, &builtin_1024x768);
1106                 if (ret)
1107                         goto err_free;
1108         }
1109
1110         drm_mode = container_of(output->base.mode_list.next,
1111                                 struct drm_mode, base.link);
1112         output->base.current = &drm_mode->base;
1113         drm_mode->base.flags =
1114                 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1115
1116         output->surface = gbm_surface_create(ec->gbm,
1117                                              output->base.current->width,
1118                                              output->base.current->height,
1119                                              GBM_FORMAT_XRGB8888,
1120                                              GBM_BO_USE_SCANOUT |
1121                                              GBM_BO_USE_RENDERING);
1122         if (!output->surface) {
1123                 fprintf(stderr, "failed to create gbm surface\n");
1124                 goto err_free;
1125         }
1126
1127         output->egl_surface =
1128                 eglCreateWindowSurface(ec->base.display, ec->base.config,
1129                                        output->surface, NULL);
1130         if (output->egl_surface == EGL_NO_SURFACE) {
1131                 fprintf(stderr, "failed to create egl surface\n");
1132                 goto err_surface;
1133         }
1134
1135         output->backlight = backlight_init(drm_device,
1136                                            connector->connector_type);
1137         if (output->backlight) {
1138                 output->base.set_backlight = drm_set_backlight;
1139                 output->base.backlight_current = drm_get_backlight(output);
1140         }
1141
1142         weston_output_init(&output->base, &ec->base, x, y,
1143                            connector->mmWidth, connector->mmHeight,
1144                            WL_OUTPUT_FLIPPED);
1145
1146         wl_list_insert(ec->base.output_list.prev, &output->base.link);
1147
1148         output->scanout_buffer_destroy_listener.func =
1149                 output_handle_scanout_buffer_destroy;
1150         output->pending_scanout_buffer_destroy_listener.func =
1151                 output_handle_pending_scanout_buffer_destroy;
1152
1153         output->next_fb_id = 0;
1154         output->base.repaint = drm_output_repaint;
1155         output->base.destroy = drm_output_destroy;
1156         output->base.assign_planes = drm_assign_planes;
1157         output->base.set_dpms = drm_set_dpms;
1158
1159         return 0;
1160
1161         eglDestroySurface(ec->base.display, output->egl_surface);
1162 err_surface:
1163         gbm_surface_destroy(output->surface);
1164 err_free:
1165         wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1166                                                         base.link) {
1167                 wl_list_remove(&drm_mode->base.link);
1168                 free(drm_mode);
1169         }
1170
1171         drmModeFreeCrtc(output->original_crtc);
1172         ec->crtc_allocator &= ~(1 << output->crtc_id);
1173         ec->connector_allocator &= ~(1 << output->connector_id);
1174         free(output);
1175
1176         return -1;
1177 }
1178
1179 static void
1180 create_sprites(struct drm_compositor *ec)
1181 {
1182         struct drm_sprite *sprite;
1183         drmModePlaneRes *plane_res;
1184         drmModePlane *plane;
1185         int i;
1186
1187         plane_res = drmModeGetPlaneResources(ec->drm.fd);
1188         if (!plane_res) {
1189                 fprintf(stderr, "failed to get plane resources: %s\n",
1190                         strerror(errno));
1191                 return;
1192         }
1193
1194         for (i = 0; i < plane_res->count_planes; i++) {
1195                 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1196                 if (!plane)
1197                         continue;
1198
1199                 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1200                                                    plane->count_formats));
1201                 if (!sprite) {
1202                         fprintf(stderr, "%s: out of memory\n",
1203                                 __func__);
1204                         free(plane);
1205                         continue;
1206                 }
1207
1208                 memset(sprite, 0, sizeof *sprite);
1209
1210                 sprite->possible_crtcs = plane->possible_crtcs;
1211                 sprite->plane_id = plane->plane_id;
1212                 sprite->surface = NULL;
1213                 sprite->pending_surface = NULL;
1214                 sprite->fb_id = 0;
1215                 sprite->pending_fb_id = 0;
1216                 sprite->destroy_listener.func = sprite_handle_buffer_destroy;
1217                 sprite->pending_destroy_listener.func =
1218                         sprite_handle_pending_buffer_destroy;
1219                 sprite->compositor = ec;
1220                 sprite->count_formats = plane->count_formats;
1221                 memcpy(sprite->formats, plane->formats,
1222                        plane->count_formats * sizeof(plane->formats[0]));
1223                 drmModeFreePlane(plane);
1224
1225                 wl_list_insert(&ec->sprite_list, &sprite->link);
1226         }
1227
1228         free(plane_res->planes);
1229         free(plane_res);
1230 }
1231
1232 static void
1233 destroy_sprites(struct drm_compositor *compositor)
1234 {
1235         struct drm_sprite *sprite, *next;
1236         struct drm_output *output;
1237
1238         output = container_of(compositor->base.output_list.next,
1239                               struct drm_output, base.link);
1240
1241         wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1242                 drmModeSetPlane(compositor->drm.fd,
1243                                 sprite->plane_id,
1244                                 output->crtc_id, 0, 0,
1245                                 0, 0, 0, 0, 0, 0, 0, 0);
1246                 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1247                 free(sprite);
1248         }
1249 }
1250
1251 static int
1252 create_outputs(struct drm_compositor *ec, int option_connector,
1253                struct udev_device *drm_device)
1254 {
1255         drmModeConnector *connector;
1256         drmModeRes *resources;
1257         int i;
1258         int x = 0, y = 0;
1259
1260         resources = drmModeGetResources(ec->drm.fd);
1261         if (!resources) {
1262                 fprintf(stderr, "drmModeGetResources failed\n");
1263                 return -1;
1264         }
1265
1266         ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
1267         if (!ec->crtcs) {
1268                 drmModeFreeResources(resources);
1269                 return -1;
1270         }
1271
1272         ec->num_crtcs = resources->count_crtcs;
1273         memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1274
1275         for (i = 0; i < resources->count_connectors; i++) {
1276                 connector = drmModeGetConnector(ec->drm.fd,
1277                                                 resources->connectors[i]);
1278                 if (connector == NULL)
1279                         continue;
1280
1281                 if (connector->connection == DRM_MODE_CONNECTED &&
1282                     (option_connector == 0 ||
1283                      connector->connector_id == option_connector)) {
1284                         if (create_output_for_connector(ec, resources,
1285                                                         connector, x, y,
1286                                                         drm_device) < 0) {
1287                                 drmModeFreeConnector(connector);
1288                                 continue;
1289                         }
1290
1291                         x += container_of(ec->base.output_list.prev,
1292                                           struct weston_output,
1293                                           link)->current->width;
1294                 }
1295
1296                 drmModeFreeConnector(connector);
1297         }
1298
1299         if (wl_list_empty(&ec->base.output_list)) {
1300                 fprintf(stderr, "No currently active connector found.\n");
1301                 drmModeFreeResources(resources);
1302                 return -1;
1303         }
1304
1305         drmModeFreeResources(resources);
1306
1307         return 0;
1308 }
1309
1310 static void
1311 update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
1312 {
1313         drmModeConnector *connector;
1314         drmModeRes *resources;
1315         struct drm_output *output, *next;
1316         int x = 0, y = 0;
1317         int x_offset = 0, y_offset = 0;
1318         uint32_t connected = 0, disconnects = 0;
1319         int i;
1320
1321         resources = drmModeGetResources(ec->drm.fd);
1322         if (!resources) {
1323                 fprintf(stderr, "drmModeGetResources failed\n");
1324                 return;
1325         }
1326
1327         /* collect new connects */
1328         for (i = 0; i < resources->count_connectors; i++) {
1329                 int connector_id = resources->connectors[i];
1330
1331                 connector = drmModeGetConnector(ec->drm.fd, connector_id);
1332                 if (connector == NULL)
1333                         continue;
1334
1335                 if (connector->connection != DRM_MODE_CONNECTED) {
1336                         drmModeFreeConnector(connector);
1337                         continue;
1338                 }
1339
1340                 connected |= (1 << connector_id);
1341
1342                 if (!(ec->connector_allocator & (1 << connector_id))) {
1343                         struct weston_output *last =
1344                                 container_of(ec->base.output_list.prev,
1345                                              struct weston_output, link);
1346
1347                         /* XXX: not yet needed, we die with 0 outputs */
1348                         if (!wl_list_empty(&ec->base.output_list))
1349                                 x = last->x + last->current->width;
1350                         else
1351                                 x = 0;
1352                         y = 0;
1353                         create_output_for_connector(ec, resources,
1354                                                     connector, x, y,
1355                                                     drm_device);
1356                         printf("connector %d connected\n", connector_id);
1357
1358                 }
1359                 drmModeFreeConnector(connector);
1360         }
1361         drmModeFreeResources(resources);
1362
1363         disconnects = ec->connector_allocator & ~connected;
1364         if (disconnects) {
1365                 wl_list_for_each_safe(output, next, &ec->base.output_list,
1366                                       base.link) {
1367                         if (x_offset != 0 || y_offset != 0) {
1368                                 weston_output_move(&output->base,
1369                                                  output->base.x - x_offset,
1370                                                  output->base.y - y_offset);
1371                         }
1372
1373                         if (disconnects & (1 << output->connector_id)) {
1374                                 disconnects &= ~(1 << output->connector_id);
1375                                 printf("connector %d disconnected\n",
1376                                        output->connector_id);
1377                                 x_offset += output->base.current->width;
1378                                 drm_output_destroy(&output->base);
1379                         }
1380                 }
1381         }
1382
1383         /* FIXME: handle zero outputs, without terminating */   
1384         if (ec->connector_allocator == 0)
1385                 wl_display_terminate(ec->base.wl_display);
1386 }
1387
1388 static int
1389 udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
1390 {
1391         const char *sysnum;
1392         const char *val;
1393
1394         sysnum = udev_device_get_sysnum(device);
1395         if (!sysnum || atoi(sysnum) != ec->drm.id)
1396                 return 0;
1397
1398         val = udev_device_get_property_value(device, "HOTPLUG");
1399         if (!val)
1400                 return 0;
1401
1402         return strcmp(val, "1") == 0;
1403 }
1404
1405 static int
1406 udev_drm_event(int fd, uint32_t mask, void *data)
1407 {
1408         struct drm_compositor *ec = data;
1409         struct udev_device *event;
1410
1411         event = udev_monitor_receive_device(ec->udev_monitor);
1412
1413         if (udev_event_is_hotplug(ec, event))
1414                 update_outputs(ec, event);
1415
1416         udev_device_unref(event);
1417
1418         return 1;
1419 }
1420
1421 static void
1422 drm_destroy(struct weston_compositor *ec)
1423 {
1424         struct drm_compositor *d = (struct drm_compositor *) ec;
1425         struct weston_input_device *input, *next;
1426
1427         weston_compositor_shutdown(ec);
1428         gbm_device_destroy(d->gbm);
1429         destroy_sprites(d);
1430         drmDropMaster(d->drm.fd);
1431         tty_destroy(d->tty);
1432
1433         wl_list_for_each_safe(input, next, &ec->input_device_list, link)
1434                 evdev_input_destroy(input);
1435
1436         free(d);
1437 }
1438
1439 static void
1440 drm_compositor_set_modes(struct drm_compositor *compositor)
1441 {
1442         struct drm_output *output;
1443         struct drm_mode *drm_mode;
1444         int ret;
1445
1446         wl_list_for_each(output, &compositor->base.output_list, base.link) {
1447                 drm_mode = (struct drm_mode *) output->base.current;
1448                 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
1449                                      output->current_fb_id, 0, 0,
1450                                      &output->connector_id, 1,
1451                                      &drm_mode->mode_info);
1452                 if (ret < 0) {
1453                         fprintf(stderr,
1454                                 "failed to set mode %dx%d for output at %d,%d: %m\n",
1455                                 drm_mode->base.width, drm_mode->base.height, 
1456                                 output->base.x, output->base.y);
1457                 }
1458         }
1459 }
1460
1461 static void
1462 vt_func(struct weston_compositor *compositor, int event)
1463 {
1464         struct drm_compositor *ec = (struct drm_compositor *) compositor;
1465         struct weston_output *output;
1466         struct weston_input_device *input;
1467         struct drm_sprite *sprite;
1468         struct drm_output *drm_output;
1469
1470         switch (event) {
1471         case TTY_ENTER_VT:
1472                 compositor->focus = 1;
1473                 if (drmSetMaster(ec->drm.fd)) {
1474                         fprintf(stderr, "failed to set master: %m\n");
1475                         wl_display_terminate(compositor->wl_display);
1476                 }
1477                 compositor->state = ec->prev_state;
1478                 drm_compositor_set_modes(ec);
1479                 weston_compositor_damage_all(compositor);
1480                 wl_list_for_each(input, &compositor->input_device_list, link)
1481                         evdev_add_devices(ec->udev, input);
1482                 break;
1483         case TTY_LEAVE_VT:
1484                 compositor->focus = 0;
1485                 ec->prev_state = compositor->state;
1486                 compositor->state = WESTON_COMPOSITOR_SLEEPING;
1487
1488                 /* If we have a repaint scheduled (either from a
1489                  * pending pageflip or the idle handler), make sure we
1490                  * cancel that so we don't try to pageflip when we're
1491                  * vt switched away.  The SLEEPING state will prevent
1492                  * further attemps at repainting.  When we switch
1493                  * back, we schedule a repaint, which will process
1494                  * pending frame callbacks. */
1495
1496                 wl_list_for_each(output, &ec->base.output_list, link) {
1497                         output->repaint_needed = 0;
1498                         drm_output_set_cursor(output, NULL);
1499                 }
1500
1501                 drm_output = container_of(ec->base.output_list.next,
1502                                           struct drm_output, base.link);
1503
1504                 wl_list_for_each(sprite, &ec->sprite_list, link)
1505                         drmModeSetPlane(ec->drm.fd,
1506                                         sprite->plane_id,
1507                                         drm_output->crtc_id, 0, 0,
1508                                         0, 0, 0, 0, 0, 0, 0, 0);
1509
1510                 wl_list_for_each(input, &compositor->input_device_list, link)
1511                         evdev_remove_devices(input);
1512
1513                 if (drmDropMaster(ec->drm.fd) < 0)
1514                         fprintf(stderr, "failed to drop master: %m\n");
1515
1516                 break;
1517         };
1518 }
1519
1520 static const char default_seat[] = "seat0";
1521
1522 static struct weston_compositor *
1523 drm_compositor_create(struct wl_display *display,
1524                       int connector, const char *seat, int tty)
1525 {
1526         struct drm_compositor *ec;
1527         struct udev_enumerate *e;
1528         struct udev_list_entry *entry;
1529         struct udev_device *device, *drm_device;
1530         const char *path, *device_seat;
1531         struct wl_event_loop *loop;
1532
1533         ec = malloc(sizeof *ec);
1534         if (ec == NULL)
1535                 return NULL;
1536
1537         memset(ec, 0, sizeof *ec);
1538         ec->udev = udev_new();
1539         if (ec->udev == NULL) {
1540                 fprintf(stderr, "failed to initialize udev context\n");
1541                 return NULL;
1542         }
1543
1544         ec->base.wl_display = display;
1545         ec->tty = tty_create(&ec->base, vt_func, tty);
1546         if (!ec->tty) {
1547                 fprintf(stderr, "failed to initialize tty\n");
1548                 free(ec);
1549                 return NULL;
1550         }
1551
1552         e = udev_enumerate_new(ec->udev);
1553         udev_enumerate_add_match_subsystem(e, "drm");
1554         udev_enumerate_add_match_sysname(e, "card[0-9]*");
1555
1556         udev_enumerate_scan_devices(e);
1557         drm_device = NULL;
1558         udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1559                 path = udev_list_entry_get_name(entry);
1560                 device = udev_device_new_from_syspath(ec->udev, path);
1561                 device_seat =
1562                         udev_device_get_property_value(device, "ID_SEAT");
1563                 if (!device_seat)
1564                         device_seat = default_seat;
1565                 if (strcmp(device_seat, seat) == 0) {
1566                         drm_device = device;
1567                         break;
1568                 }
1569                 udev_device_unref(device);
1570         }
1571
1572         if (drm_device == NULL) {
1573                 fprintf(stderr, "no drm device found\n");
1574                 return NULL;
1575         }
1576
1577         if (init_egl(ec, drm_device) < 0) {
1578                 fprintf(stderr, "failed to initialize egl\n");
1579                 return NULL;
1580         }
1581
1582         ec->base.destroy = drm_destroy;
1583
1584         ec->base.focus = 1;
1585
1586         ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
1587
1588         /* Can't init base class until we have a current egl context */
1589         if (weston_compositor_init(&ec->base, display) < 0)
1590                 return NULL;
1591
1592         wl_list_init(&ec->sprite_list);
1593         create_sprites(ec);
1594
1595         if (create_outputs(ec, connector, drm_device) < 0) {
1596                 fprintf(stderr, "failed to create output for %s\n", path);
1597                 return NULL;
1598         }
1599
1600         udev_device_unref(drm_device);
1601         udev_enumerate_unref(e);
1602         path = NULL;
1603
1604         evdev_input_create(&ec->base, ec->udev, seat);
1605
1606         loop = wl_display_get_event_loop(ec->base.wl_display);
1607         ec->drm_source =
1608                 wl_event_loop_add_fd(loop, ec->drm.fd,
1609                                      WL_EVENT_READABLE, on_drm_input, ec);
1610
1611         ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
1612         if (ec->udev_monitor == NULL) {
1613                 fprintf(stderr, "failed to intialize udev monitor\n");
1614                 return NULL;
1615         }
1616         udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
1617                                                         "drm", NULL);
1618         ec->udev_drm_source =
1619                 wl_event_loop_add_fd(loop,
1620                                      udev_monitor_get_fd(ec->udev_monitor),
1621                                      WL_EVENT_READABLE, udev_drm_event, ec);
1622
1623         if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
1624                 fprintf(stderr, "failed to enable udev-monitor receiving\n");
1625                 return NULL;
1626         }
1627
1628         return &ec->base;
1629 }
1630
1631 WL_EXPORT struct weston_compositor *
1632 backend_init(struct wl_display *display, int argc, char *argv[])
1633 {
1634         int connector = 0, tty = 0;
1635         const char *seat = default_seat;
1636
1637         const struct weston_option drm_options[] = {
1638                 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
1639                 { WESTON_OPTION_STRING, "seat", 0, &seat },
1640                 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
1641         };
1642
1643         parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
1644
1645         return drm_compositor_create(display, connector, seat, tty);
1646 }