screenshooter: Properly handle multiple outputs.
[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         uint32_t 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 > 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 void
1051 drm_output_read_pixels(struct weston_output *output_base, void *data)
1052 {
1053         struct drm_output *output = (struct drm_output *) output_base;
1054         struct drm_compositor *compositor =
1055                 (struct drm_compositor *) output->base.compositor;
1056
1057         eglMakeCurrent(compositor->base.display, output->egl_surface,
1058                         output->egl_surface, compositor->base.context);
1059
1060         glReadPixels(0, 0, output_base->current->width, output_base->current->height,
1061                                 GL_BGRA_EXT, GL_UNSIGNED_BYTE, data);
1062 }
1063
1064 static int
1065 create_output_for_connector(struct drm_compositor *ec,
1066                             drmModeRes *resources,
1067                             drmModeConnector *connector,
1068                             int x, int y, struct udev_device *drm_device)
1069 {
1070         struct drm_output *output;
1071         struct drm_mode *drm_mode, *next;
1072         drmModeEncoder *encoder;
1073         int i, ret;
1074
1075         encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[0]);
1076         if (encoder == NULL) {
1077                 fprintf(stderr, "No encoder for connector.\n");
1078                 return -1;
1079         }
1080
1081         for (i = 0; i < resources->count_crtcs; i++) {
1082                 if (encoder->possible_crtcs & (1 << i) &&
1083                     !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1084                         break;
1085         }
1086         if (i == resources->count_crtcs) {
1087                 fprintf(stderr, "No usable crtc for encoder.\n");
1088                 drmModeFreeEncoder(encoder);
1089                 return -1;
1090         }
1091
1092         output = malloc(sizeof *output);
1093         if (output == NULL) {
1094                 drmModeFreeEncoder(encoder);
1095                 return -1;
1096         }
1097
1098         memset(output, 0, sizeof *output);
1099         output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1100         output->base.make = "unknown";
1101         output->base.model = "unknown";
1102         wl_list_init(&output->base.mode_list);
1103
1104         output->crtc_id = resources->crtcs[i];
1105         ec->crtc_allocator |= (1 << output->crtc_id);
1106         output->connector_id = connector->connector_id;
1107         ec->connector_allocator |= (1 << output->connector_id);
1108
1109         output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1110         drmModeFreeEncoder(encoder);
1111
1112         for (i = 0; i < connector->count_modes; i++) {
1113                 ret = drm_output_add_mode(output, &connector->modes[i]);
1114                 if (ret)
1115                         goto err_free;
1116         }
1117
1118         if (connector->count_modes == 0) {
1119                 ret = drm_output_add_mode(output, &builtin_1024x768);
1120                 if (ret)
1121                         goto err_free;
1122         }
1123
1124         drm_mode = container_of(output->base.mode_list.next,
1125                                 struct drm_mode, base.link);
1126         output->base.current = &drm_mode->base;
1127         drm_mode->base.flags =
1128                 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1129
1130         output->surface = gbm_surface_create(ec->gbm,
1131                                              output->base.current->width,
1132                                              output->base.current->height,
1133                                              GBM_FORMAT_XRGB8888,
1134                                              GBM_BO_USE_SCANOUT |
1135                                              GBM_BO_USE_RENDERING);
1136         if (!output->surface) {
1137                 fprintf(stderr, "failed to create gbm surface\n");
1138                 goto err_free;
1139         }
1140
1141         output->egl_surface =
1142                 eglCreateWindowSurface(ec->base.display, ec->base.config,
1143                                        output->surface, NULL);
1144         if (output->egl_surface == EGL_NO_SURFACE) {
1145                 fprintf(stderr, "failed to create egl surface\n");
1146                 goto err_surface;
1147         }
1148
1149         output->backlight = backlight_init(drm_device,
1150                                            connector->connector_type);
1151         if (output->backlight) {
1152                 output->base.set_backlight = drm_set_backlight;
1153                 output->base.backlight_current = drm_get_backlight(output);
1154         }
1155
1156         weston_output_init(&output->base, &ec->base, x, y,
1157                            connector->mmWidth, connector->mmHeight,
1158                            WL_OUTPUT_FLIPPED);
1159
1160         wl_list_insert(ec->base.output_list.prev, &output->base.link);
1161
1162         output->scanout_buffer_destroy_listener.func =
1163                 output_handle_scanout_buffer_destroy;
1164         output->pending_scanout_buffer_destroy_listener.func =
1165                 output_handle_pending_scanout_buffer_destroy;
1166
1167         output->next_fb_id = 0;
1168         output->base.repaint = drm_output_repaint;
1169         output->base.destroy = drm_output_destroy;
1170         output->base.assign_planes = drm_assign_planes;
1171         output->base.read_pixels = drm_output_read_pixels;
1172         output->base.set_dpms = drm_set_dpms;
1173
1174         return 0;
1175
1176         eglDestroySurface(ec->base.display, output->egl_surface);
1177 err_surface:
1178         gbm_surface_destroy(output->surface);
1179 err_free:
1180         wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1181                                                         base.link) {
1182                 wl_list_remove(&drm_mode->base.link);
1183                 free(drm_mode);
1184         }
1185
1186         drmModeFreeCrtc(output->original_crtc);
1187         ec->crtc_allocator &= ~(1 << output->crtc_id);
1188         ec->connector_allocator &= ~(1 << output->connector_id);
1189         free(output);
1190
1191         return -1;
1192 }
1193
1194 static void
1195 create_sprites(struct drm_compositor *ec)
1196 {
1197         struct drm_sprite *sprite;
1198         drmModePlaneRes *plane_res;
1199         drmModePlane *plane;
1200         uint32_t i;
1201
1202         plane_res = drmModeGetPlaneResources(ec->drm.fd);
1203         if (!plane_res) {
1204                 fprintf(stderr, "failed to get plane resources: %s\n",
1205                         strerror(errno));
1206                 return;
1207         }
1208
1209         for (i = 0; i < plane_res->count_planes; i++) {
1210                 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1211                 if (!plane)
1212                         continue;
1213
1214                 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1215                                                    plane->count_formats));
1216                 if (!sprite) {
1217                         fprintf(stderr, "%s: out of memory\n",
1218                                 __func__);
1219                         free(plane);
1220                         continue;
1221                 }
1222
1223                 memset(sprite, 0, sizeof *sprite);
1224
1225                 sprite->possible_crtcs = plane->possible_crtcs;
1226                 sprite->plane_id = plane->plane_id;
1227                 sprite->surface = NULL;
1228                 sprite->pending_surface = NULL;
1229                 sprite->fb_id = 0;
1230                 sprite->pending_fb_id = 0;
1231                 sprite->destroy_listener.func = sprite_handle_buffer_destroy;
1232                 sprite->pending_destroy_listener.func =
1233                         sprite_handle_pending_buffer_destroy;
1234                 sprite->compositor = ec;
1235                 sprite->count_formats = plane->count_formats;
1236                 memcpy(sprite->formats, plane->formats,
1237                        plane->count_formats * sizeof(plane->formats[0]));
1238                 drmModeFreePlane(plane);
1239
1240                 wl_list_insert(&ec->sprite_list, &sprite->link);
1241         }
1242
1243         free(plane_res->planes);
1244         free(plane_res);
1245 }
1246
1247 static void
1248 destroy_sprites(struct drm_compositor *compositor)
1249 {
1250         struct drm_sprite *sprite, *next;
1251         struct drm_output *output;
1252
1253         output = container_of(compositor->base.output_list.next,
1254                               struct drm_output, base.link);
1255
1256         wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1257                 drmModeSetPlane(compositor->drm.fd,
1258                                 sprite->plane_id,
1259                                 output->crtc_id, 0, 0,
1260                                 0, 0, 0, 0, 0, 0, 0, 0);
1261                 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1262                 free(sprite);
1263         }
1264 }
1265
1266 static int
1267 create_outputs(struct drm_compositor *ec, uint32_t option_connector,
1268                struct udev_device *drm_device)
1269 {
1270         drmModeConnector *connector;
1271         drmModeRes *resources;
1272         int i;
1273         int x = 0, y = 0;
1274
1275         resources = drmModeGetResources(ec->drm.fd);
1276         if (!resources) {
1277                 fprintf(stderr, "drmModeGetResources failed\n");
1278                 return -1;
1279         }
1280
1281         ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
1282         if (!ec->crtcs) {
1283                 drmModeFreeResources(resources);
1284                 return -1;
1285         }
1286
1287         ec->num_crtcs = resources->count_crtcs;
1288         memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1289
1290         for (i = 0; i < resources->count_connectors; i++) {
1291                 connector = drmModeGetConnector(ec->drm.fd,
1292                                                 resources->connectors[i]);
1293                 if (connector == NULL)
1294                         continue;
1295
1296                 if (connector->connection == DRM_MODE_CONNECTED &&
1297                     (option_connector == 0 ||
1298                      connector->connector_id == option_connector)) {
1299                         if (create_output_for_connector(ec, resources,
1300                                                         connector, x, y,
1301                                                         drm_device) < 0) {
1302                                 drmModeFreeConnector(connector);
1303                                 continue;
1304                         }
1305
1306                         x += container_of(ec->base.output_list.prev,
1307                                           struct weston_output,
1308                                           link)->current->width;
1309                 }
1310
1311                 drmModeFreeConnector(connector);
1312         }
1313
1314         if (wl_list_empty(&ec->base.output_list)) {
1315                 fprintf(stderr, "No currently active connector found.\n");
1316                 drmModeFreeResources(resources);
1317                 return -1;
1318         }
1319
1320         drmModeFreeResources(resources);
1321
1322         return 0;
1323 }
1324
1325 static void
1326 update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
1327 {
1328         drmModeConnector *connector;
1329         drmModeRes *resources;
1330         struct drm_output *output, *next;
1331         int x = 0, y = 0;
1332         int x_offset = 0, y_offset = 0;
1333         uint32_t connected = 0, disconnects = 0;
1334         int i;
1335
1336         resources = drmModeGetResources(ec->drm.fd);
1337         if (!resources) {
1338                 fprintf(stderr, "drmModeGetResources failed\n");
1339                 return;
1340         }
1341
1342         /* collect new connects */
1343         for (i = 0; i < resources->count_connectors; i++) {
1344                 int connector_id = resources->connectors[i];
1345
1346                 connector = drmModeGetConnector(ec->drm.fd, connector_id);
1347                 if (connector == NULL)
1348                         continue;
1349
1350                 if (connector->connection != DRM_MODE_CONNECTED) {
1351                         drmModeFreeConnector(connector);
1352                         continue;
1353                 }
1354
1355                 connected |= (1 << connector_id);
1356
1357                 if (!(ec->connector_allocator & (1 << connector_id))) {
1358                         struct weston_output *last =
1359                                 container_of(ec->base.output_list.prev,
1360                                              struct weston_output, link);
1361
1362                         /* XXX: not yet needed, we die with 0 outputs */
1363                         if (!wl_list_empty(&ec->base.output_list))
1364                                 x = last->x + last->current->width;
1365                         else
1366                                 x = 0;
1367                         y = 0;
1368                         create_output_for_connector(ec, resources,
1369                                                     connector, x, y,
1370                                                     drm_device);
1371                         printf("connector %d connected\n", connector_id);
1372
1373                 }
1374                 drmModeFreeConnector(connector);
1375         }
1376         drmModeFreeResources(resources);
1377
1378         disconnects = ec->connector_allocator & ~connected;
1379         if (disconnects) {
1380                 wl_list_for_each_safe(output, next, &ec->base.output_list,
1381                                       base.link) {
1382                         if (x_offset != 0 || y_offset != 0) {
1383                                 weston_output_move(&output->base,
1384                                                  output->base.x - x_offset,
1385                                                  output->base.y - y_offset);
1386                         }
1387
1388                         if (disconnects & (1 << output->connector_id)) {
1389                                 disconnects &= ~(1 << output->connector_id);
1390                                 printf("connector %d disconnected\n",
1391                                        output->connector_id);
1392                                 x_offset += output->base.current->width;
1393                                 drm_output_destroy(&output->base);
1394                         }
1395                 }
1396         }
1397
1398         /* FIXME: handle zero outputs, without terminating */   
1399         if (ec->connector_allocator == 0)
1400                 wl_display_terminate(ec->base.wl_display);
1401 }
1402
1403 static int
1404 udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
1405 {
1406         const char *sysnum;
1407         const char *val;
1408
1409         sysnum = udev_device_get_sysnum(device);
1410         if (!sysnum || atoi(sysnum) != ec->drm.id)
1411                 return 0;
1412
1413         val = udev_device_get_property_value(device, "HOTPLUG");
1414         if (!val)
1415                 return 0;
1416
1417         return strcmp(val, "1") == 0;
1418 }
1419
1420 static int
1421 udev_drm_event(int fd, uint32_t mask, void *data)
1422 {
1423         struct drm_compositor *ec = data;
1424         struct udev_device *event;
1425
1426         event = udev_monitor_receive_device(ec->udev_monitor);
1427
1428         if (udev_event_is_hotplug(ec, event))
1429                 update_outputs(ec, event);
1430
1431         udev_device_unref(event);
1432
1433         return 1;
1434 }
1435
1436 static void
1437 drm_destroy(struct weston_compositor *ec)
1438 {
1439         struct drm_compositor *d = (struct drm_compositor *) ec;
1440         struct weston_input_device *input, *next;
1441
1442         wl_list_for_each_safe(input, next, &ec->input_device_list, link)
1443                 evdev_input_destroy(input);
1444
1445         wl_event_source_remove(d->udev_drm_source);
1446         wl_event_source_remove(d->drm_source);
1447
1448         weston_compositor_shutdown(ec);
1449
1450         gbm_device_destroy(d->gbm);
1451         destroy_sprites(d);
1452         drmDropMaster(d->drm.fd);
1453         tty_destroy(d->tty);
1454
1455         free(d);
1456 }
1457
1458 static void
1459 drm_compositor_set_modes(struct drm_compositor *compositor)
1460 {
1461         struct drm_output *output;
1462         struct drm_mode *drm_mode;
1463         int ret;
1464
1465         wl_list_for_each(output, &compositor->base.output_list, base.link) {
1466                 drm_mode = (struct drm_mode *) output->base.current;
1467                 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
1468                                      output->current_fb_id, 0, 0,
1469                                      &output->connector_id, 1,
1470                                      &drm_mode->mode_info);
1471                 if (ret < 0) {
1472                         fprintf(stderr,
1473                                 "failed to set mode %dx%d for output at %d,%d: %m\n",
1474                                 drm_mode->base.width, drm_mode->base.height, 
1475                                 output->base.x, output->base.y);
1476                 }
1477         }
1478 }
1479
1480 static void
1481 vt_func(struct weston_compositor *compositor, int event)
1482 {
1483         struct drm_compositor *ec = (struct drm_compositor *) compositor;
1484         struct weston_output *output;
1485         struct weston_input_device *input;
1486         struct drm_sprite *sprite;
1487         struct drm_output *drm_output;
1488
1489         switch (event) {
1490         case TTY_ENTER_VT:
1491                 compositor->focus = 1;
1492                 if (drmSetMaster(ec->drm.fd)) {
1493                         fprintf(stderr, "failed to set master: %m\n");
1494                         wl_display_terminate(compositor->wl_display);
1495                 }
1496                 compositor->state = ec->prev_state;
1497                 drm_compositor_set_modes(ec);
1498                 weston_compositor_damage_all(compositor);
1499                 wl_list_for_each(input, &compositor->input_device_list, link)
1500                         evdev_add_devices(ec->udev, input);
1501                 break;
1502         case TTY_LEAVE_VT:
1503                 compositor->focus = 0;
1504                 ec->prev_state = compositor->state;
1505                 compositor->state = WESTON_COMPOSITOR_SLEEPING;
1506
1507                 /* If we have a repaint scheduled (either from a
1508                  * pending pageflip or the idle handler), make sure we
1509                  * cancel that so we don't try to pageflip when we're
1510                  * vt switched away.  The SLEEPING state will prevent
1511                  * further attemps at repainting.  When we switch
1512                  * back, we schedule a repaint, which will process
1513                  * pending frame callbacks. */
1514
1515                 wl_list_for_each(output, &ec->base.output_list, link) {
1516                         output->repaint_needed = 0;
1517                         drm_output_set_cursor(output, NULL);
1518                 }
1519
1520                 drm_output = container_of(ec->base.output_list.next,
1521                                           struct drm_output, base.link);
1522
1523                 wl_list_for_each(sprite, &ec->sprite_list, link)
1524                         drmModeSetPlane(ec->drm.fd,
1525                                         sprite->plane_id,
1526                                         drm_output->crtc_id, 0, 0,
1527                                         0, 0, 0, 0, 0, 0, 0, 0);
1528
1529                 wl_list_for_each(input, &compositor->input_device_list, link)
1530                         evdev_remove_devices(input);
1531
1532                 if (drmDropMaster(ec->drm.fd) < 0)
1533                         fprintf(stderr, "failed to drop master: %m\n");
1534
1535                 break;
1536         };
1537 }
1538
1539 static const char default_seat[] = "seat0";
1540
1541 static struct weston_compositor *
1542 drm_compositor_create(struct wl_display *display,
1543                       int connector, const char *seat, int tty)
1544 {
1545         struct drm_compositor *ec;
1546         struct udev_enumerate *e;
1547         struct udev_list_entry *entry;
1548         struct udev_device *device, *drm_device;
1549         const char *path, *device_seat;
1550         struct wl_event_loop *loop;
1551
1552         ec = malloc(sizeof *ec);
1553         if (ec == NULL)
1554                 return NULL;
1555
1556         memset(ec, 0, sizeof *ec);
1557         ec->udev = udev_new();
1558         if (ec->udev == NULL) {
1559                 fprintf(stderr, "failed to initialize udev context\n");
1560                 return NULL;
1561         }
1562
1563         ec->base.wl_display = display;
1564         ec->tty = tty_create(&ec->base, vt_func, tty);
1565         if (!ec->tty) {
1566                 fprintf(stderr, "failed to initialize tty\n");
1567                 free(ec);
1568                 return NULL;
1569         }
1570
1571         e = udev_enumerate_new(ec->udev);
1572         udev_enumerate_add_match_subsystem(e, "drm");
1573         udev_enumerate_add_match_sysname(e, "card[0-9]*");
1574
1575         udev_enumerate_scan_devices(e);
1576         drm_device = NULL;
1577         udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1578                 path = udev_list_entry_get_name(entry);
1579                 device = udev_device_new_from_syspath(ec->udev, path);
1580                 device_seat =
1581                         udev_device_get_property_value(device, "ID_SEAT");
1582                 if (!device_seat)
1583                         device_seat = default_seat;
1584                 if (strcmp(device_seat, seat) == 0) {
1585                         drm_device = device;
1586                         break;
1587                 }
1588                 udev_device_unref(device);
1589         }
1590
1591         if (drm_device == NULL) {
1592                 fprintf(stderr, "no drm device found\n");
1593                 return NULL;
1594         }
1595
1596         if (init_egl(ec, drm_device) < 0) {
1597                 fprintf(stderr, "failed to initialize egl\n");
1598                 return NULL;
1599         }
1600
1601         ec->base.destroy = drm_destroy;
1602
1603         ec->base.focus = 1;
1604
1605         ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
1606
1607         /* Can't init base class until we have a current egl context */
1608         if (weston_compositor_init(&ec->base, display) < 0)
1609                 return NULL;
1610
1611         wl_list_init(&ec->sprite_list);
1612         create_sprites(ec);
1613
1614         if (create_outputs(ec, connector, drm_device) < 0) {
1615                 fprintf(stderr, "failed to create output for %s\n", path);
1616                 return NULL;
1617         }
1618
1619         udev_device_unref(drm_device);
1620         udev_enumerate_unref(e);
1621         path = NULL;
1622
1623         evdev_input_create(&ec->base, ec->udev, seat);
1624
1625         loop = wl_display_get_event_loop(ec->base.wl_display);
1626         ec->drm_source =
1627                 wl_event_loop_add_fd(loop, ec->drm.fd,
1628                                      WL_EVENT_READABLE, on_drm_input, ec);
1629
1630         ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
1631         if (ec->udev_monitor == NULL) {
1632                 fprintf(stderr, "failed to intialize udev monitor\n");
1633                 return NULL;
1634         }
1635         udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
1636                                                         "drm", NULL);
1637         ec->udev_drm_source =
1638                 wl_event_loop_add_fd(loop,
1639                                      udev_monitor_get_fd(ec->udev_monitor),
1640                                      WL_EVENT_READABLE, udev_drm_event, ec);
1641
1642         if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
1643                 fprintf(stderr, "failed to enable udev-monitor receiving\n");
1644                 return NULL;
1645         }
1646
1647         return &ec->base;
1648 }
1649
1650 WL_EXPORT struct weston_compositor *
1651 backend_init(struct wl_display *display, int argc, char *argv[])
1652 {
1653         int connector = 0, tty = 0;
1654         const char *seat = default_seat;
1655
1656         const struct weston_option drm_options[] = {
1657                 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
1658                 { WESTON_OPTION_STRING, "seat", 0, &seat },
1659                 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
1660         };
1661
1662         parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
1663
1664         return drm_compositor_create(display, connector, seat, tty);
1665 }