compositor: Set EGL_PLATFORM env variable for each backend.
[profile/ivi/weston.git] / compositor / compositor-drm.c
1 /*
2  * Copyright © 2008-2010 Kristian Høgsberg
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18
19 #define _GNU_SOURCE
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26
27 #include <xf86drm.h>
28 #include <xf86drmMode.h>
29
30 #include "compositor.h"
31
32 struct drm_compositor {
33         struct wlsc_compositor base;
34
35         struct udev *udev;
36         struct wl_event_source *drm_source;
37
38         struct udev_monitor *udev_monitor;
39         struct wl_event_source *udev_drm_source;
40
41         struct {
42                 int fd;
43         } drm;
44         uint32_t crtc_allocator;
45         uint32_t connector_allocator;
46         struct tty *tty;
47
48         PFNEGLCREATEDRMIMAGEMESA create_drm_image;
49         PFNEGLEXPORTDRMIMAGEMESA export_drm_image;
50 };
51
52 struct drm_output {
53         struct wlsc_output   base;
54
55         drmModeModeInfo mode;
56         uint32_t crtc_id;
57         uint32_t connector_id;
58         GLuint rbo[2];
59         uint32_t fb_id[2];
60         EGLImageKHR image[2];
61         uint32_t current;       
62
63         struct wlsc_surface *scanout_surface;
64
65         uint32_t fs_surf_fb_id;
66         uint32_t pending_fs_surf_fb_id;
67 };
68
69 static int
70 drm_output_prepare_render(struct wlsc_output *output_base)
71 {
72         struct drm_output *output = (struct drm_output *) output_base;
73
74         glFramebufferRenderbuffer(GL_FRAMEBUFFER,
75                                   GL_COLOR_ATTACHMENT0,
76                                   GL_RENDERBUFFER,
77                                   output->rbo[output->current]);
78
79         if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
80                 return -1;
81
82         return 0;
83 }
84
85 static int
86 drm_output_present(struct wlsc_output *output_base)
87 {
88         struct drm_output *output = (struct drm_output *) output_base;
89         struct drm_compositor *c =
90                 (struct drm_compositor *) output->base.compositor;
91         uint32_t fb_id = 0;
92
93         if (drm_output_prepare_render(&output->base))
94                 return -1;
95         glFlush();
96
97         output->current ^= 1;
98
99         if (output->scanout_surface != NULL) {
100                 output->scanout_surface = NULL;
101                 fb_id = output->fs_surf_fb_id;
102         } else {
103                 fb_id = output->fb_id[output->current ^ 1];
104         }
105
106         drmModePageFlip(c->drm.fd, output->crtc_id,
107                         fb_id,
108                         DRM_MODE_PAGE_FLIP_EVENT, output);
109
110         return 0;
111 }
112
113 static void
114 page_flip_handler(int fd, unsigned int frame,
115                   unsigned int sec, unsigned int usec, void *data)
116 {
117         struct drm_output *output = (struct drm_output *) data;
118         struct drm_compositor *c =
119                 (struct drm_compositor *) output->base.compositor;
120         uint32_t msecs;
121
122         if (output->pending_fs_surf_fb_id) {
123                 drmModeRmFB(c->drm.fd, output->pending_fs_surf_fb_id);
124                 output->pending_fs_surf_fb_id = 0;
125         }
126
127         if (output->fs_surf_fb_id) {
128                 output->pending_fs_surf_fb_id = output->fs_surf_fb_id;
129                 output->fs_surf_fb_id = 0;
130         }
131
132         msecs = sec * 1000 + usec / 1000;
133         wlsc_output_finish_frame(&output->base, msecs);
134 }
135
136 static int
137 drm_output_prepare_scanout_surface(struct wlsc_output *output_base,
138                                    struct wlsc_surface *es)
139 {
140         struct drm_output *output = (struct drm_output *) output_base;
141         struct drm_compositor *c =
142                 (struct drm_compositor *) output->base.compositor;
143         EGLint handle, stride;
144         int ret;
145         uint32_t fb_id = 0;
146
147         if (es->x != output->base.x ||
148             es->y != output->base.y ||
149             es->width != output->base.width ||
150             es->height != output->base.height ||
151             es->image == EGL_NO_IMAGE_KHR)
152                 return -1;
153
154         c->export_drm_image(c->base.display,
155                             es->image, NULL, &handle, &stride);
156
157         if (handle == 0)
158                 return -1;
159
160         ret = drmModeAddFB(c->drm.fd,
161                            output->base.width, output->base.height,
162                            32, 32, stride, handle, &fb_id);
163
164         if (ret)
165                 return -1;
166
167         output->fs_surf_fb_id = fb_id;
168         output->scanout_surface = es;
169
170         return 0;
171 }
172
173 static int
174 drm_output_set_cursor(struct wlsc_output *output_base,
175                       struct wlsc_input_device *eid)
176 {
177         struct drm_output *output = (struct drm_output *) output_base;
178         struct drm_compositor *c =
179                 (struct drm_compositor *) output->base.compositor;
180         EGLint handle, stride;
181         int ret = -1;
182         pixman_region32_t cursor_region;
183
184         if (eid == NULL) {
185                 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
186                 return 0;
187         }
188
189         pixman_region32_init_rect(&cursor_region,
190                                   eid->sprite->x, eid->sprite->y,
191                                   eid->sprite->width, eid->sprite->height);
192
193         pixman_region32_intersect_rect(&cursor_region, &cursor_region,
194                                        output->base.x, output->base.y,
195                                        output->base.width, output->base.height);
196
197         if (!pixman_region32_not_empty(&cursor_region)) {
198                 ret = 0;
199                 goto out;
200         }
201
202         if (eid->sprite->image == EGL_NO_IMAGE_KHR)
203                 goto out;
204
205         if (eid->sprite->width > 64 || eid->sprite->height > 64)
206                 goto out;
207         
208         c->export_drm_image(c->base.display, eid->sprite->image,
209                             NULL, &handle, &stride);
210
211         if (stride != 64 * 4) {
212                 fprintf(stderr, "info: cursor stride is != 64\n");
213                 goto out;
214         }
215
216         ret = drmModeSetCursor(c->drm.fd, output->crtc_id, handle, 64, 64);
217         if (ret) {
218                 fprintf(stderr, "failed to set cursor: %s\n", strerror(-ret));
219                 goto out;
220         }
221
222         ret = drmModeMoveCursor(c->drm.fd, output->crtc_id,
223                                 eid->sprite->x - output->base.x,
224                                 eid->sprite->y - output->base.y);
225         if (ret) {
226                 fprintf(stderr, "failed to move cursor: %s\n", strerror(-ret));
227                 goto out;
228         }
229
230         printf("info: set hardware cursor\n");
231
232 out:
233         pixman_region32_fini(&cursor_region);
234         if (ret)
235                 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
236         return ret;
237 }
238
239 static int
240 on_drm_input(int fd, uint32_t mask, void *data)
241 {
242         drmEventContext evctx;
243
244         memset(&evctx, 0, sizeof evctx);
245         evctx.version = DRM_EVENT_CONTEXT_VERSION;
246         evctx.page_flip_handler = page_flip_handler;
247         drmHandleEvent(fd, &evctx);
248
249         return 1;
250 }
251
252 static int
253 init_egl(struct drm_compositor *ec, struct udev_device *device)
254 {
255         EGLint major, minor;
256         const char *extensions, *filename;
257         int fd;
258         static const EGLint context_attribs[] = {
259                 EGL_CONTEXT_CLIENT_VERSION, 2,
260                 EGL_NONE
261         };
262
263         filename = udev_device_get_devnode(device);
264         fd = open(filename, O_RDWR, O_CLOEXEC);
265         if (fd < 0) {
266                 /* Probably permissions error */
267                 fprintf(stderr, "couldn't open %s, skipping\n",
268                         udev_device_get_devnode(device));
269                 return -1;
270         }
271
272         setenv("EGL_PLATFORM", "drm", 1);
273         ec->drm.fd = fd;
274         ec->base.display = eglGetDisplay(FD_TO_EGL_NATIVE_DPY(ec->drm.fd));
275         if (ec->base.display == NULL) {
276                 fprintf(stderr, "failed to create display\n");
277                 return -1;
278         }
279
280         if (!eglInitialize(ec->base.display, &major, &minor)) {
281                 fprintf(stderr, "failed to initialize display\n");
282                 return -1;
283         }
284
285         extensions = eglQueryString(ec->base.display, EGL_EXTENSIONS);
286         if (!strstr(extensions, "EGL_KHR_surfaceless_opengl")) {
287                 fprintf(stderr, "EGL_KHR_surfaceless_opengl not available\n");
288                 return -1;
289         }
290
291         if (!eglBindAPI(EGL_OPENGL_ES_API)) {
292                 fprintf(stderr, "failed to bind api EGL_OPENGL_ES_API\n");
293                 return -1;
294         }
295
296         ec->base.context = eglCreateContext(ec->base.display, NULL,
297                                             EGL_NO_CONTEXT, context_attribs);
298         if (ec->base.context == NULL) {
299                 fprintf(stderr, "failed to create context\n");
300                 return -1;
301         }
302
303         if (!eglMakeCurrent(ec->base.display, EGL_NO_SURFACE,
304                             EGL_NO_SURFACE, ec->base.context)) {
305                 fprintf(stderr, "failed to make context current\n");
306                 return -1;
307         }
308
309         return 0;
310 }
311
312 static drmModeModeInfo builtin_1024x768 = {
313         63500,                  /* clock */
314         1024, 1072, 1176, 1328, 0,
315         768, 771, 775, 798, 0,
316         59920,
317         DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC,
318         0,
319         "1024x768"
320 };
321
322 static int
323 create_output_for_connector(struct drm_compositor *ec,
324                             drmModeRes *resources,
325                             drmModeConnector *connector,
326                             int x, int y)
327 {
328         struct drm_output *output;
329         drmModeEncoder *encoder;
330         drmModeModeInfo *mode;
331         int i, ret;
332         EGLint handle, stride, attribs[] = {
333                 EGL_WIDTH,              0,
334                 EGL_HEIGHT,             0,
335                 EGL_DRM_BUFFER_FORMAT_MESA,     EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
336                 EGL_DRM_BUFFER_USE_MESA,        EGL_DRM_BUFFER_USE_SCANOUT_MESA,
337                 EGL_NONE
338         };
339
340         output = malloc(sizeof *output);
341         if (output == NULL)
342                 return -1;
343
344         if (connector->count_modes > 0) 
345                 mode = &connector->modes[0];
346         else
347                 mode = &builtin_1024x768;
348
349         encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[0]);
350         if (encoder == NULL) {
351                 fprintf(stderr, "No encoder for connector.\n");
352                 return -1;
353         }
354
355         for (i = 0; i < resources->count_crtcs; i++) {
356                 if (encoder->possible_crtcs & (1 << i) &&
357                     !(ec->crtc_allocator & (1 << resources->crtcs[i])))
358                         break;
359         }
360         if (i == resources->count_crtcs) {
361                 fprintf(stderr, "No usable crtc for encoder.\n");
362                 return -1;
363         }
364
365         memset(output, 0, sizeof *output);
366         wlsc_output_init(&output->base, &ec->base, x, y,
367                          mode->hdisplay, mode->vdisplay, 0);
368
369         output->crtc_id = resources->crtcs[i];
370         ec->crtc_allocator |= (1 << output->crtc_id);
371
372         output->connector_id = connector->connector_id;
373         ec->connector_allocator |= (1 << output->connector_id);
374         output->mode = *mode;
375
376         drmModeFreeEncoder(encoder);
377
378         glGenRenderbuffers(2, output->rbo);
379         for (i = 0; i < 2; i++) {
380                 glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
381
382                 attribs[1] = output->base.width;
383                 attribs[3] = output->base.height;
384                 output->image[i] =
385                         ec->create_drm_image(ec->base.display, attribs);
386                 ec->base.image_target_renderbuffer_storage(GL_RENDERBUFFER,
387                                                            output->image[i]);
388                 ec->export_drm_image(ec->base.display, output->image[i],
389                                      NULL, &handle, &stride);
390
391                 ret = drmModeAddFB(ec->drm.fd,
392                                    output->base.width, output->base.height,
393                                    32, 32, stride, handle, &output->fb_id[i]);
394                 if (ret) {
395                         fprintf(stderr, "failed to add fb %d: %m\n", i);
396                         return -1;
397                 }
398         }
399
400         output->current = 0;
401         glFramebufferRenderbuffer(GL_FRAMEBUFFER,
402                                   GL_COLOR_ATTACHMENT0,
403                                   GL_RENDERBUFFER,
404                                   output->rbo[output->current]);
405         ret = drmModeSetCrtc(ec->drm.fd, output->crtc_id,
406                              output->fb_id[output->current ^ 1], 0, 0,
407                              &output->connector_id, 1, &output->mode);
408         if (ret) {
409                 fprintf(stderr, "failed to set mode: %m\n");
410                 return -1;
411         }
412
413         output->scanout_surface = NULL;
414         output->base.prepare_render = drm_output_prepare_render;
415         output->base.present = drm_output_present;
416         output->base.prepare_scanout_surface =
417                 drm_output_prepare_scanout_surface;
418         output->base.set_hardware_cursor = drm_output_set_cursor;
419
420         wl_list_insert(ec->base.output_list.prev, &output->base.link);
421
422         return 0;
423 }
424
425 static int
426 create_outputs(struct drm_compositor *ec, int option_connector)
427 {
428         drmModeConnector *connector;
429         drmModeRes *resources;
430         int i;
431         int x = 0, y = 0;
432
433         resources = drmModeGetResources(ec->drm.fd);
434         if (!resources) {
435                 fprintf(stderr, "drmModeGetResources failed\n");
436                 return -1;
437         }
438
439         for (i = 0; i < resources->count_connectors; i++) {
440                 connector = drmModeGetConnector(ec->drm.fd, resources->connectors[i]);
441                 if (connector == NULL)
442                         continue;
443
444                 if (connector->connection == DRM_MODE_CONNECTED &&
445                     (option_connector == 0 ||
446                      connector->connector_id == option_connector))
447                         if (create_output_for_connector(ec, resources,
448                                                         connector, x, y) < 0)
449                                 return -1;
450
451                 x += container_of(ec->base.output_list.prev, struct wlsc_output,
452                                   link)->width;
453
454                 drmModeFreeConnector(connector);
455         }
456
457         if (wl_list_empty(&ec->base.output_list)) {
458                 fprintf(stderr, "No currently active connector found.\n");
459                 return -1;
460         }
461
462         drmModeFreeResources(resources);
463
464         return 0;
465 }
466
467 static int
468 destroy_output(struct drm_output *output)
469 {
470         struct drm_compositor *ec =
471                 (struct drm_compositor *) output->base.compositor;
472         int i;
473
474         glFramebufferRenderbuffer(GL_FRAMEBUFFER,
475                                   GL_COLOR_ATTACHMENT0,
476                                   GL_RENDERBUFFER,
477                                   0);
478
479         glBindRenderbuffer(GL_RENDERBUFFER, 0);
480         glDeleteRenderbuffers(2, output->rbo);
481
482         for (i = 0; i < 2; i++) {
483                 ec->base.destroy_image(ec->base.display, output->image[i]);
484                 drmModeRmFB(ec->drm.fd, output->fb_id[i]);
485         }
486         
487         ec->crtc_allocator &= ~(1 << output->crtc_id);
488         ec->connector_allocator &= ~(1 << output->connector_id);
489
490         wlsc_output_destroy(&output->base);
491         wl_list_remove(&output->base.link);
492
493         free(output);
494
495         return 0;
496 }
497
498 static void
499 update_outputs(struct drm_compositor *ec)
500 {
501         drmModeConnector *connector;
502         drmModeRes *resources;
503         struct drm_output *output, *next;
504         int x = 0, y = 0;
505         int x_offset = 0, y_offset = 0;
506         uint32_t connected = 0, disconnects = 0;
507         int i;
508
509         resources = drmModeGetResources(ec->drm.fd);
510         if (!resources) {
511                 fprintf(stderr, "drmModeGetResources failed\n");
512                 return;
513         }
514
515         /* collect new connects */
516         for (i = 0; i < resources->count_connectors; i++) {
517                 connector =
518                         drmModeGetConnector(ec->drm.fd,
519                                             resources->connectors[i]);
520                 if (connector == NULL ||
521                     connector->connection != DRM_MODE_CONNECTED)
522                         continue;
523
524                 connected |= (1 << connector->connector_id);
525                 
526                 if (!(ec->connector_allocator & (1 << connector->connector_id))) {
527                         struct wlsc_output *last_output =
528                                 container_of(ec->base.output_list.prev,
529                                              struct wlsc_output, link);
530
531                         /* XXX: not yet needed, we die with 0 outputs */
532                         if (!wl_list_empty(&ec->base.output_list))
533                                 x = last_output->x + last_output->width;
534                         else
535                                 x = 0;
536                         y = 0;
537                         create_output_for_connector(ec, resources,
538                                                     connector, x, y);
539                         printf("connector %d connected\n",
540                                connector->connector_id);
541                                 
542                 }
543                 drmModeFreeConnector(connector);
544         }
545         drmModeFreeResources(resources);
546
547         disconnects = ec->connector_allocator & ~connected;
548         if (disconnects) {
549                 wl_list_for_each_safe(output, next, &ec->base.output_list,
550                                       base.link) {
551                         if (x_offset != 0 || y_offset != 0) {
552                                 wlsc_output_move(&output->base,
553                                                  output->base.x - x_offset,
554                                                  output->base.y - y_offset);
555                         }
556
557                         if (disconnects & (1 << output->connector_id)) {
558                                 disconnects &= ~(1 << output->connector_id);
559                                 printf("connector %d disconnected\n",
560                                        output->connector_id);
561                                 x_offset += output->base.width;
562                                 destroy_output(output);
563                         }
564                 }
565         }
566
567         /* FIXME: handle zero outputs, without terminating */   
568         if (ec->connector_allocator == 0)
569                 wl_display_terminate(ec->base.wl_display);
570 }
571
572 static int
573 udev_event_is_hotplug(struct udev_device *device)
574 {
575         struct udev_list_entry *list, *hotplug_entry;
576         
577         list = udev_device_get_properties_list_entry(device);
578
579         hotplug_entry = udev_list_entry_get_by_name(list, "HOTPLUG");
580         if (hotplug_entry == NULL)
581                 return 0;
582
583         return strcmp(udev_list_entry_get_value(hotplug_entry), "1") == 0;
584 }
585
586 static int
587 udev_drm_event(int fd, uint32_t mask, void *data)
588 {
589         struct drm_compositor *ec = data;
590         struct udev_device *event;
591
592         event = udev_monitor_receive_device(ec->udev_monitor);
593         
594         if (udev_event_is_hotplug(event))
595                 update_outputs(ec);
596
597         udev_device_unref(event);
598
599         return 1;
600 }
601
602 static EGLImageKHR
603 drm_compositor_create_cursor_image(struct wlsc_compositor *ec,
604                                    int32_t width, int32_t height)
605 {
606         static const EGLint image_attribs[] = {
607                 EGL_WIDTH, 64,
608                 EGL_HEIGHT, 64,
609                 EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
610                 EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_CURSOR_MESA,
611                 EGL_NONE
612         };
613         struct drm_compositor *c = (struct drm_compositor *) ec;
614
615         if (width > 64 || height > 64)
616                 return EGL_NO_IMAGE_KHR;
617
618         return c->create_drm_image(ec->display, image_attribs);
619 }
620
621 static void
622 drm_destroy(struct wlsc_compositor *ec)
623 {
624         struct drm_compositor *d = (struct drm_compositor *) ec;
625
626         tty_destroy(d->tty);
627
628         free(d);
629 }
630
631 static void
632 vt_func(struct wlsc_compositor *compositor, int event)
633 {
634         struct drm_compositor *ec = (struct drm_compositor *) compositor;
635         struct wlsc_output *output;
636
637         switch (event) {
638         case TTY_ENTER_VT:
639                 compositor->focus = 1;
640                 drmSetMaster(ec->drm.fd);
641                 compositor->state = WLSC_COMPOSITOR_ACTIVE;
642                 wlsc_compositor_damage_all(compositor);
643                 break;
644         case TTY_LEAVE_VT:
645                 compositor->focus = 0;
646                 compositor->state = WLSC_COMPOSITOR_SLEEPING;
647                 drmDropMaster(ec->drm.fd);
648
649                 wl_list_for_each(output, &ec->base.output_list, link)
650                         drm_output_set_cursor(output, NULL);
651
652                 break;
653         };
654 }
655
656 static struct wlsc_compositor *
657 drm_compositor_create(struct wl_display *display, int connector)
658 {
659         struct drm_compositor *ec;
660         struct udev_enumerate *e;
661         struct udev_list_entry *entry;
662         struct udev_device *device;
663         const char *path;
664         struct wl_event_loop *loop;
665
666         ec = malloc(sizeof *ec);
667         if (ec == NULL)
668                 return NULL;
669
670         memset(ec, 0, sizeof *ec);
671         ec->udev = udev_new();
672         if (ec->udev == NULL) {
673                 fprintf(stderr, "failed to initialize udev context\n");
674                 return NULL;
675         }
676
677         e = udev_enumerate_new(ec->udev);
678         udev_enumerate_add_match_subsystem(e, "drm");
679         udev_enumerate_add_match_property(e, "WAYLAND_SEAT", "1");
680         udev_enumerate_scan_devices(e);
681         device = NULL;
682         udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
683                 path = udev_list_entry_get_name(entry);
684                 device = udev_device_new_from_syspath(ec->udev, path);
685                 break;
686         }
687         udev_enumerate_unref(e);
688
689         if (device == NULL) {
690                 fprintf(stderr, "no drm device found\n");
691                 return NULL;
692         }
693
694         ec->base.wl_display = display;
695         if (init_egl(ec, device) < 0) {
696                 fprintf(stderr, "failed to initialize egl\n");
697                 return NULL;
698         }
699
700         ec->base.destroy = drm_destroy;
701         ec->base.create_cursor_image = drm_compositor_create_cursor_image;
702
703         ec->base.focus = 1;
704
705         glGenFramebuffers(1, &ec->base.fbo);
706         glBindFramebuffer(GL_FRAMEBUFFER, ec->base.fbo);
707
708         ec->create_drm_image =
709                 (void *) eglGetProcAddress("eglCreateDRMImageMESA");
710         ec->export_drm_image =
711                 (void *) eglGetProcAddress("eglExportDRMImageMESA");
712
713         /* Can't init base class until we have a current egl context */
714         if (wlsc_compositor_init(&ec->base, display) < 0)
715                 return NULL;
716
717         if (create_outputs(ec, connector) < 0) {
718                 fprintf(stderr, "failed to create output for %s\n", path);
719                 return NULL;
720         }
721
722         evdev_input_add_devices(&ec->base, ec->udev);
723
724         loop = wl_display_get_event_loop(ec->base.wl_display);
725         ec->drm_source =
726                 wl_event_loop_add_fd(loop, ec->drm.fd,
727                                      WL_EVENT_READABLE, on_drm_input, ec);
728         ec->tty = tty_create(&ec->base, vt_func);
729
730         ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
731         if (ec->udev_monitor == NULL) {
732                 fprintf(stderr, "failed to intialize udev monitor\n");
733                 return NULL;
734         }
735         udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
736                                                         "drm", NULL);
737         ec->udev_drm_source =
738                 wl_event_loop_add_fd(loop, udev_monitor_get_fd(ec->udev_monitor),
739                                      WL_EVENT_READABLE, udev_drm_event, ec);
740
741         if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
742                 fprintf(stderr, "failed to enable udev-monitor receiving\n");
743                 return NULL;
744         }
745
746         return &ec->base;
747 }
748
749 struct wlsc_compositor *
750 backend_init(struct wl_display *display, char *options);
751
752 WL_EXPORT struct wlsc_compositor *
753 backend_init(struct wl_display *display, char *options)
754 {
755         int connector = 0, i;
756         char *p, *value;
757
758         static char * const tokens[] = { "connector", NULL };
759         
760         p = options;
761         while (i = getsubopt(&p, tokens, &value), i != -1) {
762                 switch (i) {
763                 case 0:
764                         connector = strtol(value, NULL, 0);
765                         break;
766                 }
767         }
768
769         return drm_compositor_create(display, connector);
770 }