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