Merge remote-tracking branch 'bnf/fullscreen-pageflip'
[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 #define GL_GLEXT_PROTOTYPES
31 #define EGL_EGLEXT_PROTOTYPES
32 #include <GLES2/gl2.h>
33 #include <GLES2/gl2ext.h>
34 #include <EGL/egl.h>
35 #include <EGL/eglext.h>
36
37 #include "compositor.h"
38
39 struct drm_compositor {
40         struct wlsc_compositor base;
41
42         struct udev *udev;
43         struct wl_event_source *drm_source;
44
45         struct udev_monitor *udev_monitor;
46         struct wl_event_source *udev_drm_source;
47
48         struct {
49                 int fd;
50         } drm;
51         uint32_t crtc_allocator;
52         uint32_t connector_allocator;
53         struct tty *tty;
54 };
55
56 struct drm_output {
57         struct wlsc_output   base;
58
59         drmModeModeInfo mode;
60         uint32_t crtc_id;
61         uint32_t connector_id;
62         GLuint rbo[2];
63         uint32_t fb_id[2];
64         EGLImageKHR image[2];
65         uint32_t current;       
66
67         uint32_t fs_surf_fb_id;
68         uint32_t pending_fs_surf_fb_id;
69 };
70
71 static int
72 drm_output_prepare_render(struct wlsc_output *output_base)
73 {
74         struct drm_output *output = (struct drm_output *) output_base;
75
76         glFramebufferRenderbuffer(GL_FRAMEBUFFER,
77                                   GL_COLOR_ATTACHMENT0,
78                                   GL_RENDERBUFFER,
79                                   output->rbo[output->current]);
80
81         if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
82                 return -1;
83
84         return 0;
85 }
86
87 static int
88 drm_output_present(struct wlsc_output *output_base)
89 {
90         struct drm_output *output = (struct drm_output *) output_base;
91         struct drm_compositor *c =
92                 (struct drm_compositor *) output->base.compositor;
93         int ret;
94         uint32_t fb_id = 0;
95
96         if (drm_output_prepare_render(&output->base))
97                 return -1;
98         glFlush();
99
100         output->current ^= 1;
101
102         if (output->base.scanout_surface) {
103                 EGLint handle, stride;
104
105                 eglExportDRMImageMESA(c->base.display,
106                                       output->base.scanout_surface->image,
107                                       NULL, &handle, &stride);
108
109                 ret = drmModeAddFB(c->drm.fd,
110                                    output->base.width, output->base.height,
111                                    32, 32, stride, handle,
112                                    &output->fs_surf_fb_id);
113                 if (ret)
114                         return -1;
115
116                 printf("pageflip to fullscreen buffer: %d\n", handle);
117
118                 fb_id = output->fs_surf_fb_id;
119         } else {
120                 fb_id = output->fb_id[output->current ^ 1];
121         }
122
123         drmModePageFlip(c->drm.fd, output->crtc_id,
124                         fb_id,
125                         DRM_MODE_PAGE_FLIP_EVENT, output);
126
127         return 0;
128 }
129
130 static void
131 page_flip_handler(int fd, unsigned int frame,
132                   unsigned int sec, unsigned int usec, void *data)
133 {
134         struct drm_output *output = (struct drm_output *) data;
135         struct drm_compositor *c =
136                 (struct drm_compositor *) output->base.compositor;
137         uint32_t msecs;
138
139         if (output->pending_fs_surf_fb_id) {
140                 drmModeRmFB(c->drm.fd, output->pending_fs_surf_fb_id);
141                 output->pending_fs_surf_fb_id = 0;
142         }
143
144         if (output->fs_surf_fb_id) {
145                 output->pending_fs_surf_fb_id = output->fs_surf_fb_id;
146                 output->fs_surf_fb_id = 0;
147         }
148
149         msecs = sec * 1000 + usec / 1000;
150         wlsc_output_finish_frame(&output->base, msecs);
151 }
152
153 static int
154 drm_output_image_is_scanoutable(struct wlsc_output *output_base,
155                                 EGLImageKHR image)
156 {
157         struct drm_output *output = (struct drm_output *) output_base;
158         struct drm_compositor *c =
159                 (struct drm_compositor *) output->base.compositor;
160         EGLint handle, stride;
161         int ret;
162         uint32_t fb_id = 0;
163
164         eglExportDRMImageMESA(c->base.display, image,
165                               NULL, &handle, &stride);
166
167         ret = drmModeAddFB(c->drm.fd,
168                            output->base.width, output->base.height,
169                            32, 32, stride, handle,
170                            &fb_id);
171         if (ret)
172                 return 0;
173
174         /* FIXME: change interface to keep this fb_id,
175          * to be used directly in next pageflip? */
176         if (fb_id)
177                 drmModeRmFB(c->drm.fd, fb_id);
178
179         return fb_id != 0;
180 }
181
182 static int
183 drm_output_set_cursor(struct wlsc_output *output_base,
184                       struct wl_input_device *input)
185 {
186         struct drm_output *output = (struct drm_output *) output_base;
187         struct drm_compositor *c =
188                 (struct drm_compositor *) output->base.compositor;
189         struct wlsc_input_device *eid = (struct wlsc_input_device *) input;
190         EGLint handle, stride;
191         int ret = -1;
192         pixman_region32_t cursor_region;
193
194         pixman_region32_init_rect(&cursor_region,
195                                   eid->sprite->x, eid->sprite->y,
196                                   eid->sprite->width, eid->sprite->height);
197
198         pixman_region32_intersect_rect(&cursor_region, &cursor_region,
199                                        output->base.x, output->base.y,
200                                        output->base.width, output->base.height);
201
202         if (!pixman_region32_not_empty(&cursor_region)) {
203                 ret = 0;
204                 goto out;
205         }
206
207         if (eid->sprite->image == EGL_NO_IMAGE_KHR)
208                 goto out;
209
210         if (eid->sprite->width > 64 || eid->sprite->height > 64)
211                 goto out;
212         
213         eglExportDRMImageMESA(c->base.display, eid->sprite->image,
214                               NULL, &handle, &stride);
215
216         if (stride != 64 * 4) {
217                 fprintf(stderr, "info: cursor stride is != 64\n");
218                 goto out;
219         }
220
221         ret = drmModeSetCursor(c->drm.fd, output->crtc_id, handle, 64, 64);
222         if (ret) {
223                 fprintf(stderr, "failed to set cursor: %s\n", strerror(-ret));
224                 goto out;
225         }
226
227         ret = drmModeMoveCursor(c->drm.fd, output->crtc_id,
228                                 eid->sprite->x - output->base.x,
229                                 eid->sprite->y - output->base.y);
230         if (ret) {
231                 fprintf(stderr, "failed to move cursor: %s\n", strerror(-ret));
232                 goto out;
233         }
234
235         printf("info: set hardware cursor\n");
236
237 out:
238         pixman_region32_fini(&cursor_region);
239         if (ret)
240                 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
241         return ret;
242 }
243
244 static void
245 on_drm_input(int fd, uint32_t mask, void *data)
246 {
247         drmEventContext evctx;
248
249         memset(&evctx, 0, sizeof evctx);
250         evctx.version = DRM_EVENT_CONTEXT_VERSION;
251         evctx.page_flip_handler = page_flip_handler;
252         drmHandleEvent(fd, &evctx);
253 }
254
255 static int
256 init_egl(struct drm_compositor *ec, struct udev_device *device)
257 {
258         EGLint major, minor;
259         const char *extensions, *filename;
260         int fd;
261         static const EGLint context_attribs[] = {
262                 EGL_CONTEXT_CLIENT_VERSION, 2,
263                 EGL_NONE
264         };
265
266         filename = udev_device_get_devnode(device);
267         fd = open(filename, O_RDWR, O_CLOEXEC);
268         if (fd < 0) {
269                 /* Probably permissions error */
270                 fprintf(stderr, "couldn't open %s, skipping\n",
271                         udev_device_get_devnode(device));
272                 return -1;
273         }
274
275         ec->drm.fd = fd;
276         ec->base.display = eglGetDRMDisplayMESA(ec->drm.fd);
277         if (ec->base.display == NULL) {
278                 fprintf(stderr, "failed to create display\n");
279                 return -1;
280         }
281
282         if (!eglInitialize(ec->base.display, &major, &minor)) {
283                 fprintf(stderr, "failed to initialize display\n");
284                 return -1;
285         }
286
287         extensions = eglQueryString(ec->base.display, EGL_EXTENSIONS);
288         if (!strstr(extensions, "EGL_KHR_surfaceless_opengl")) {
289                 fprintf(stderr, "EGL_KHR_surfaceless_opengl not available\n");
290                 return -1;
291         }
292
293         if (!eglBindAPI(EGL_OPENGL_ES_API)) {
294                 fprintf(stderr, "failed to bind api EGL_OPENGL_ES_API\n");
295                 return -1;
296         }
297
298         ec->base.context = eglCreateContext(ec->base.display, NULL,
299                                             EGL_NO_CONTEXT, context_attribs);
300         if (ec->base.context == NULL) {
301                 fprintf(stderr, "failed to create context\n");
302                 return -1;
303         }
304
305         if (!eglMakeCurrent(ec->base.display, EGL_NO_SURFACE,
306                             EGL_NO_SURFACE, ec->base.context)) {
307                 fprintf(stderr, "failed to make context current\n");
308                 return -1;
309         }
310
311         return 0;
312 }
313
314 static drmModeModeInfo builtin_1024x768 = {
315         63500,                  /* clock */
316         1024, 1072, 1176, 1328, 0,
317         768, 771, 775, 798, 0,
318         59920,
319         DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC,
320         0,
321         "1024x768"
322 };
323
324 static int
325 create_output_for_connector(struct drm_compositor *ec,
326                             drmModeRes *resources,
327                             drmModeConnector *connector,
328                             int x, int y)
329 {
330         struct drm_output *output;
331         drmModeEncoder *encoder;
332         drmModeModeInfo *mode;
333         int i, ret;
334         EGLint handle, stride, attribs[] = {
335                 EGL_WIDTH,              0,
336                 EGL_HEIGHT,             0,
337                 EGL_DRM_BUFFER_FORMAT_MESA,     EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
338                 EGL_DRM_BUFFER_USE_MESA,        EGL_DRM_BUFFER_USE_SCANOUT_MESA,
339                 EGL_NONE
340         };
341
342         output = malloc(sizeof *output);
343         if (output == NULL)
344                 return -1;
345
346         if (connector->count_modes > 0) 
347                 mode = &connector->modes[0];
348         else
349                 mode = &builtin_1024x768;
350
351         encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[0]);
352         if (encoder == NULL) {
353                 fprintf(stderr, "No encoder for connector.\n");
354                 return -1;
355         }
356
357         for (i = 0; i < resources->count_crtcs; i++) {
358                 if (encoder->possible_crtcs & (1 << i) &&
359                     !(ec->crtc_allocator & (1 << resources->crtcs[i])))
360                         break;
361         }
362         if (i == resources->count_crtcs) {
363                 fprintf(stderr, "No usable crtc for encoder.\n");
364                 return -1;
365         }
366
367         memset(output, 0, sizeof *output);
368         wlsc_output_init(&output->base, &ec->base, x, y,
369                          mode->hdisplay, mode->vdisplay, 0);
370
371         output->crtc_id = resources->crtcs[i];
372         ec->crtc_allocator |= (1 << output->crtc_id);
373
374         output->connector_id = connector->connector_id;
375         ec->connector_allocator |= (1 << output->connector_id);
376         output->mode = *mode;
377
378         drmModeFreeEncoder(encoder);
379
380         glGenRenderbuffers(2, output->rbo);
381         for (i = 0; i < 2; i++) {
382                 glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
383
384                 attribs[1] = output->base.width;
385                 attribs[3] = output->base.height;
386                 output->image[i] =
387                         eglCreateDRMImageMESA(ec->base.display, attribs);
388                 glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
389                                                        output->image[i]);
390                 eglExportDRMImageMESA(ec->base.display, output->image[i],
391                                       NULL, &handle, &stride);
392
393                 ret = drmModeAddFB(ec->drm.fd,
394                                    output->base.width, output->base.height,
395                                    32, 32, stride, handle, &output->fb_id[i]);
396                 if (ret) {
397                         fprintf(stderr, "failed to add fb %d: %m\n", i);
398                         return -1;
399                 }
400         }
401
402         output->current = 0;
403         glFramebufferRenderbuffer(GL_FRAMEBUFFER,
404                                   GL_COLOR_ATTACHMENT0,
405                                   GL_RENDERBUFFER,
406                                   output->rbo[output->current]);
407         ret = drmModeSetCrtc(ec->drm.fd, output->crtc_id,
408                              output->fb_id[output->current ^ 1], 0, 0,
409                              &output->connector_id, 1, &output->mode);
410         if (ret) {
411                 fprintf(stderr, "failed to set mode: %m\n");
412                 return -1;
413         }
414
415         output->base.prepare_render = drm_output_prepare_render;
416         output->base.present = drm_output_present;
417         output->base.image_is_scanoutable = drm_output_image_is_scanoutable;
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                 eglDestroyImageKHR(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 void
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
600 static EGLImageKHR
601 drm_compositor_create_cursor_image(struct wlsc_compositor *ec,
602                                    int32_t width, int32_t height)
603 {
604         EGLint image_attribs[] = {
605                 EGL_WIDTH, 0,
606                 EGL_HEIGHT, 0,
607                 EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
608                 0, 0,
609                 EGL_NONE
610         };
611         EGLint stride, name;
612         EGLImageKHR tmp_image, image;
613
614         if (width > 64 || height > 64)
615                 return EGL_NO_IMAGE_KHR;
616
617         image_attribs[1] = 64;
618         image_attribs[3] = 64;
619         image_attribs[6] = EGL_DRM_BUFFER_USE_MESA;
620         image_attribs[7] = EGL_DRM_BUFFER_USE_SCANOUT_MESA;
621
622         tmp_image = eglCreateDRMImageMESA(ec->display, image_attribs);
623
624         eglExportDRMImageMESA(ec->display, tmp_image, &name, NULL, &stride);
625
626         if (stride == 64)
627                 return tmp_image;
628
629         /* recreate image width stide 64 forced */
630         image_attribs[1] = width;
631         image_attribs[3] = height;
632         image_attribs[6] = EGL_DRM_BUFFER_STRIDE_MESA;
633         image_attribs[7] = 64;
634
635         image = eglCreateImageKHR(ec->display, EGL_NO_CONTEXT, EGL_DRM_BUFFER_MESA,
636                                   (EGLClientBuffer)(intptr_t) name, image_attribs);
637         eglExportDRMImageMESA(ec->display, image, &name, NULL, &stride);
638
639         eglDestroyImageKHR(ec->display, tmp_image);
640
641         return image;
642 }
643
644 static void
645 drm_destroy(struct wlsc_compositor *ec)
646 {
647         struct drm_compositor *d = (struct drm_compositor *) ec;
648
649         tty_destroy(d->tty);
650
651         free(d);
652 }
653
654 struct wlsc_compositor *
655 drm_compositor_create(struct wl_display *display, int connector)
656 {
657         struct drm_compositor *ec;
658         struct udev_enumerate *e;
659         struct udev_list_entry *entry;
660         struct udev_device *device;
661         const char *path;
662         struct wl_event_loop *loop;
663
664         ec = malloc(sizeof *ec);
665         if (ec == NULL)
666                 return NULL;
667
668         memset(ec, 0, sizeof *ec);
669         ec->udev = udev_new();
670         if (ec->udev == NULL) {
671                 fprintf(stderr, "failed to initialize udev context\n");
672                 return NULL;
673         }
674
675         e = udev_enumerate_new(ec->udev);
676         udev_enumerate_add_match_subsystem(e, "drm");
677         udev_enumerate_add_match_property(e, "WAYLAND_SEAT", "1");
678         udev_enumerate_scan_devices(e);
679         device = NULL;
680         udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
681                 path = udev_list_entry_get_name(entry);
682                 device = udev_device_new_from_syspath(ec->udev, path);
683                 break;
684         }
685         udev_enumerate_unref(e);
686
687         if (device == NULL) {
688                 fprintf(stderr, "no drm device found\n");
689                 return NULL;
690         }
691
692         ec->base.wl_display = display;
693         if (init_egl(ec, device) < 0) {
694                 fprintf(stderr, "failed to initialize egl\n");
695                 return NULL;
696         }
697
698         ec->base.destroy = drm_destroy;
699         ec->base.create_cursor_image = drm_compositor_create_cursor_image;
700
701         ec->base.focus = 1;
702
703         glGenFramebuffers(1, &ec->base.fbo);
704         glBindFramebuffer(GL_FRAMEBUFFER, ec->base.fbo);
705
706         /* Can't init base class until we have a current egl context */
707         if (wlsc_compositor_init(&ec->base, display) < 0)
708                 return NULL;
709
710         if (create_outputs(ec, connector) < 0) {
711                 fprintf(stderr, "failed to create output for %s\n", path);
712                 return NULL;
713         }
714
715         evdev_input_add_devices(&ec->base, ec->udev);
716
717         loop = wl_display_get_event_loop(ec->base.wl_display);
718         ec->drm_source =
719                 wl_event_loop_add_fd(loop, ec->drm.fd,
720                                      WL_EVENT_READABLE, on_drm_input, ec);
721         ec->tty = tty_create(&ec->base);
722
723         ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
724         if (ec->udev_monitor == NULL) {
725                 fprintf(stderr, "failed to intialize udev monitor\n");
726                 return NULL;
727         }
728         udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
729                                                         "drm", NULL);
730         ec->udev_drm_source =
731                 wl_event_loop_add_fd(loop, udev_monitor_get_fd(ec->udev_monitor),
732                                      WL_EVENT_READABLE, udev_drm_event, ec);
733
734         if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
735                 fprintf(stderr, "failed to enable udev-monitor receiving\n");
736                 return NULL;
737         }
738
739         return &ec->base;
740 }