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