Split native drm part of compositor out
[profile/ivi/wayland.git] / 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 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24
25 #include <signal.h>
26 #include <linux/vt.h>
27 #include <linux/input.h>
28
29 #define GL_GLEXT_PROTOTYPES
30 #define EGL_EGLEXT_PROTOTYPES
31 #include <GLES2/gl2.h>
32 #include <GLES2/gl2ext.h>
33 #include <EGL/egl.h>
34 #include <EGL/eglext.h>
35
36 #include "wayland.h"
37 #include "wayland-protocol.h"
38 #include "compositor.h"
39
40 struct evdev_input_device {
41         struct wlsc_input_device *device;
42         struct wl_event_source *source;
43         int tool, new_x, new_y;
44         int base_x, base_y;
45         int fd;
46 };
47
48 static void evdev_input_device_data(int fd, uint32_t mask, void *data)
49 {
50         struct evdev_input_device *device = data;
51         struct input_event ev[8], *e, *end;
52         int len, value, dx, dy, absolute_event;
53         int x, y;
54
55         dx = 0;
56         dy = 0;
57         absolute_event = 0;
58         x = device->device->x;
59         y = device->device->y;
60
61         len = read(fd, &ev, sizeof ev);
62         if (len < 0 || len % sizeof e[0] != 0) {
63                 /* FIXME: handle error... reopen device? */;
64                 return;
65         }
66
67         e = ev;
68         end = (void *) ev + len;
69         for (e = ev; e < end; e++) {
70                 /* Get the signed value, earlier kernels had this as unsigned */
71                 value = e->value;
72
73                 switch (e->type) {
74                 case EV_REL:
75                         switch (e->code) {
76                         case REL_X:
77                                 dx += value;
78                                 break;
79
80                         case REL_Y:
81                                 dy += value;
82                                 break;
83                         }
84                         break;
85
86                 case EV_ABS:
87                         absolute_event = 1;
88                         switch (e->code) {
89                         case ABS_X:
90                                 if (device->new_x) {
91                                         device->base_x = x - value;
92                                         device->new_x = 0;
93                                 }
94                                 x = device->base_x + value;
95                                 break;
96                         case ABS_Y:
97                                 if (device->new_y) {
98                                         device->base_y = y - value;
99                                         device->new_y = 0;
100                                 }
101                                 y = device->base_y + value;
102                                 break;
103                         }
104                         break;
105
106                 case EV_KEY:
107                         if (value == 2)
108                                 break;
109
110                         switch (e->code) {
111                         case BTN_TOUCH:
112                         case BTN_TOOL_PEN:
113                         case BTN_TOOL_RUBBER:
114                         case BTN_TOOL_BRUSH:
115                         case BTN_TOOL_PENCIL:
116                         case BTN_TOOL_AIRBRUSH:
117                         case BTN_TOOL_FINGER:
118                         case BTN_TOOL_MOUSE:
119                         case BTN_TOOL_LENS:
120                                 if (device->tool == 0 && value) {
121                                         device->new_x = 1;
122                                         device->new_y = 1;
123                                 }
124                                 device->tool = value ? e->code : 0;
125                                 break;
126
127                         case BTN_LEFT:
128                         case BTN_RIGHT:
129                         case BTN_MIDDLE:
130                         case BTN_SIDE:
131                         case BTN_EXTRA:
132                         case BTN_FORWARD:
133                         case BTN_BACK:
134                         case BTN_TASK:
135                                 notify_button(device->device, e->code, value);
136                                 break;
137
138                         default:
139                                 notify_key(device->device, e->code, value);
140                                 break;
141                         }
142                 }
143         }
144
145         if (dx != 0 || dy != 0)
146                 notify_motion(device->device, x + dx, y + dy);
147         if (absolute_event && device->tool)
148                 notify_motion(device->device, x, y);
149 }
150
151 static struct evdev_input_device *
152 evdev_input_device_create(struct wlsc_input_device *master,
153                           struct wl_display *display, const char *path)
154 {
155         struct evdev_input_device *device;
156         struct wl_event_loop *loop;
157
158         device = malloc(sizeof *device);
159         if (device == NULL)
160                 return NULL;
161
162         device->tool = 1;
163         device->new_x = 1;
164         device->new_y = 1;
165         device->device = master;
166
167         device->fd = open(path, O_RDONLY);
168         if (device->fd < 0) {
169                 free(device);
170                 fprintf(stderr, "couldn't create pointer for %s: %m\n", path);
171                 return NULL;
172         }
173
174         loop = wl_display_get_event_loop(display);
175         device->source = wl_event_loop_add_fd(loop, device->fd,
176                                               WL_EVENT_READABLE,
177                                               evdev_input_device_data, device);
178         if (device->source == NULL) {
179                 close(device->fd);
180                 free(device);
181                 return NULL;
182         }
183
184         return device;
185 }
186
187 void
188 wlsc_compositor_present_drm(struct wlsc_compositor *ec)
189 {
190         struct wlsc_output *output;
191
192         wl_list_for_each(output, &ec->output_list, link) {
193                 drmModePageFlip(ec->drm_fd, output->crtc_id,
194                                 output->fb_id[output->current ^ 1],
195                                 DRM_MODE_PAGE_FLIP_EVENT, output);
196         }       
197 }
198
199 static void
200 page_flip_handler(int fd, unsigned int frame,
201                   unsigned int sec, unsigned int usec, void *data)
202 {
203         struct wlsc_output *output = data;
204         struct wlsc_compositor *compositor = output->compositor;
205         uint32_t msecs;
206
207         msecs = sec * 1000 + usec / 1000;
208         wlsc_compositor_finish_frame(compositor, msecs);
209 }
210
211 static void
212 on_drm_input(int fd, uint32_t mask, void *data)
213 {
214         drmEventContext evctx;
215
216         memset(&evctx, 0, sizeof evctx);
217         evctx.version = DRM_EVENT_CONTEXT_VERSION;
218         evctx.page_flip_handler = page_flip_handler;
219         drmHandleEvent(fd, &evctx);
220 }
221
222 static int
223 init_egl(struct wlsc_compositor *ec, struct udev_device *device)
224 {
225         struct wl_event_loop *loop;
226         EGLint major, minor, count;
227         EGLConfig config;
228         PFNEGLGETTYPEDDISPLAYMESA get_typed_display_mesa;
229
230         static const EGLint config_attribs[] = {
231                 EGL_SURFACE_TYPE,               0,
232                 EGL_NO_SURFACE_CAPABLE_MESA,    EGL_OPENGL_BIT,
233                 EGL_RENDERABLE_TYPE,            EGL_OPENGL_BIT,
234                 EGL_NONE
235         };
236
237         get_typed_display_mesa =
238                 (PFNEGLGETTYPEDDISPLAYMESA) eglGetProcAddress("eglGetTypedDisplayMESA");
239         if (get_typed_display_mesa == NULL) {
240                 fprintf(stderr, "eglGetTypedDisplayMESA() not found\n");
241                 return -1;
242         }
243
244         ec->base.device = strdup(udev_device_get_devnode(device));
245         ec->drm_fd = open(ec->base.device, O_RDWR);
246         if (ec->drm_fd < 0) {
247                 /* Probably permissions error */
248                 fprintf(stderr, "couldn't open %s, skipping\n",
249                         udev_device_get_devnode(device));
250                 return -1;
251         }
252
253         ec->display = get_typed_display_mesa(EGL_DRM_DISPLAY_TYPE_MESA,
254                                              (void *) ec->drm_fd);
255         if (ec->display == NULL) {
256                 fprintf(stderr, "failed to create display\n");
257                 return -1;
258         }
259
260         if (!eglInitialize(ec->display, &major, &minor)) {
261                 fprintf(stderr, "failed to initialize display\n");
262                 return -1;
263         }
264
265         if (!eglChooseConfig(ec->display, config_attribs, &config, 1, &count) ||
266             count == 0) {
267                 fprintf(stderr, "eglChooseConfig() failed\n");
268                 return -1;
269         }
270
271         eglBindAPI(EGL_OPENGL_API);
272         ec->context = eglCreateContext(ec->display, config, EGL_NO_CONTEXT, NULL);
273         if (ec->context == NULL) {
274                 fprintf(stderr, "failed to create context\n");
275                 return -1;
276         }
277
278         if (!eglMakeCurrent(ec->display, EGL_NO_SURFACE, EGL_NO_SURFACE, ec->context)) {
279                 fprintf(stderr, "failed to make context current\n");
280                 return -1;
281         }
282
283         loop = wl_display_get_event_loop(ec->wl_display);
284         ec->drm_source =
285                 wl_event_loop_add_fd(loop, ec->drm_fd,
286                                      WL_EVENT_READABLE, on_drm_input, ec);
287
288         return 0;
289 }
290
291 static drmModeModeInfo builtin_1024x768 = {
292         63500,                  /* clock */
293         1024, 1072, 1176, 1328, 0,
294         768, 771, 775, 798, 0,
295         59920,
296         DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC,
297         0,
298         "1024x768"
299 };
300
301 static int
302 create_output_for_connector(struct wlsc_compositor *ec,
303                             drmModeRes *resources,
304                             drmModeConnector *connector)
305 {
306         struct wlsc_output *output;
307         drmModeEncoder *encoder;
308         drmModeModeInfo *mode;
309         int i, ret;
310         EGLint handle, stride, attribs[] = {
311                 EGL_WIDTH,              0,
312                 EGL_HEIGHT,             0,
313                 EGL_IMAGE_FORMAT_MESA,  EGL_IMAGE_FORMAT_ARGB8888_MESA,
314                 EGL_IMAGE_USE_MESA,     EGL_IMAGE_USE_SCANOUT_MESA,
315                 EGL_NONE
316         };
317
318         output = malloc(sizeof *output);
319         if (output == NULL)
320                 return -1;
321
322         if (connector->count_modes > 0) 
323                 mode = &connector->modes[0];
324         else
325                 mode = &builtin_1024x768;
326
327         encoder = drmModeGetEncoder(ec->drm_fd, connector->encoders[0]);
328         if (encoder == NULL) {
329                 fprintf(stderr, "No encoder for connector.\n");
330                 return -1;
331         }
332
333         for (i = 0; i < resources->count_crtcs; i++) {
334                 if (encoder->possible_crtcs & (1 << i))
335                         break;
336         }
337         if (i == resources->count_crtcs) {
338                 fprintf(stderr, "No usable crtc for encoder.\n");
339                 return -1;
340         }
341
342         output->compositor = ec;
343         output->crtc_id = resources->crtcs[i];
344         output->connector_id = connector->connector_id;
345         output->mode = *mode;
346         output->x = 0;
347         output->y = 0;
348         output->width = mode->hdisplay;
349         output->height = mode->vdisplay;
350
351         drmModeFreeEncoder(encoder);
352
353         glGenRenderbuffers(2, output->rbo);
354         for (i = 0; i < 2; i++) {
355                 glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
356
357                 attribs[1] = output->width;
358                 attribs[3] = output->height;
359                 output->image[i] = eglCreateDRMImageMESA(ec->display, attribs);
360                 glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, output->image[i]);
361                 eglExportDRMImageMESA(ec->display, output->image[i], NULL, &handle, &stride);
362
363                 ret = drmModeAddFB(ec->drm_fd, output->width, output->height,
364                                    32, 32, stride, handle, &output->fb_id[i]);
365                 if (ret) {
366                         fprintf(stderr, "failed to add fb %d: %m\n", i);
367                         return -1;
368                 }
369         }
370
371         output->current = 0;
372         glFramebufferRenderbuffer(GL_FRAMEBUFFER,
373                                   GL_COLOR_ATTACHMENT0,
374                                   GL_RENDERBUFFER,
375                                   output->rbo[output->current]);
376         ret = drmModeSetCrtc(ec->drm_fd, output->crtc_id,
377                              output->fb_id[output->current ^ 1], 0, 0,
378                              &output->connector_id, 1, &output->mode);
379         if (ret) {
380                 fprintf(stderr, "failed to set mode: %m\n");
381                 return -1;
382         }
383
384         wl_list_insert(ec->output_list.prev, &output->link);
385
386         return 0;
387 }
388
389 static int
390 create_outputs(struct wlsc_compositor *ec)
391 {
392         drmModeConnector *connector;
393         drmModeRes *resources;
394         int i;
395
396         resources = drmModeGetResources(ec->drm_fd);
397         if (!resources) {
398                 fprintf(stderr, "drmModeGetResources failed\n");
399                 return -1;
400         }
401
402         for (i = 0; i < resources->count_connectors; i++) {
403                 connector = drmModeGetConnector(ec->drm_fd, resources->connectors[i]);
404                 if (connector == NULL)
405                         continue;
406
407                 if (connector->connection == DRM_MODE_CONNECTED &&
408                     (option_connector == 0 ||
409                      connector->connector_id == option_connector))
410                         if (create_output_for_connector(ec, resources, connector) < 0)
411                                 return -1;
412
413                 drmModeFreeConnector(connector);
414         }
415
416         if (wl_list_empty(&ec->output_list)) {
417                 fprintf(stderr, "No currently active connector found.\n");
418                 return -1;
419         }
420
421         drmModeFreeResources(resources);
422
423         return 0;
424 }
425
426 static void on_enter_vt(int signal_number, void *data)
427 {
428         struct wlsc_compositor *ec = data;
429         struct wlsc_output *output;
430         int ret;
431
432         ret = drmSetMaster(ec->drm_fd);
433         if (ret) {
434                 fprintf(stderr, "failed to set drm master\n");
435                 kill(0, SIGTERM);
436                 return;
437         }
438
439         fprintf(stderr, "enter vt\n");
440
441         ioctl(ec->tty_fd, VT_RELDISP, VT_ACKACQ);
442         ec->vt_active = 1;
443
444         wl_list_for_each(output, &ec->output_list, link) {
445                 ret = drmModeSetCrtc(ec->drm_fd, output->crtc_id,
446                                      output->fb_id[output->current ^ 1], 0, 0,
447                                      &output->connector_id, 1, &output->mode);
448                 if (ret)
449                         fprintf(stderr, "failed to set mode for connector %d: %m\n",
450                                 output->connector_id);
451         }
452 }
453
454 static void on_leave_vt(int signal_number, void *data)
455 {
456         struct wlsc_compositor *ec = data;
457         int ret;
458
459         ret = drmDropMaster(ec->drm_fd);
460         if (ret) {
461                 fprintf(stderr, "failed to drop drm master\n");
462                 kill(0, SIGTERM);
463                 return;
464         }
465
466         ioctl (ec->tty_fd, VT_RELDISP, 1);
467         ec->vt_active = 0;
468 }
469
470 static void
471 on_tty_input(int fd, uint32_t mask, void *data)
472 {
473         struct wlsc_compositor *ec = data;
474
475         /* Ignore input to tty.  We get keyboard events from evdev
476          */
477         tcflush(ec->tty_fd, TCIFLUSH);
478 }
479
480 static void on_term_signal(int signal_number, void *data)
481 {
482         struct wlsc_compositor *ec = data;
483
484         if (tcsetattr(ec->tty_fd, TCSANOW, &ec->terminal_attributes) < 0)
485                 fprintf(stderr, "could not restore terminal to canonical mode\n");
486
487         exit(0);
488 }
489
490 static int setup_tty(struct wlsc_compositor *ec, struct wl_event_loop *loop)
491 {
492         struct termios raw_attributes;
493         struct vt_mode mode = { 0 };
494
495         ec->tty_fd = open("/dev/tty0", O_RDWR | O_NOCTTY);
496         if (ec->tty_fd <= 0) {
497                 fprintf(stderr, "failed to open active tty: %m\n");
498                 return -1;
499         }
500
501         if (tcgetattr(ec->tty_fd, &ec->terminal_attributes) < 0) {
502                 fprintf(stderr, "could not get terminal attributes: %m\n");
503                 return -1;
504         }
505
506         /* Ignore control characters and disable echo */
507         raw_attributes = ec->terminal_attributes;
508         cfmakeraw(&raw_attributes);
509
510         /* Fix up line endings to be normal (cfmakeraw hoses them) */
511         raw_attributes.c_oflag |= OPOST | OCRNL;
512
513         if (tcsetattr(ec->tty_fd, TCSANOW, &raw_attributes) < 0)
514                 fprintf(stderr, "could not put terminal into raw mode: %m\n");
515
516         ec->term_signal_source =
517                 wl_event_loop_add_signal(loop, SIGTERM, on_term_signal, ec);
518
519         ec->tty_input_source =
520                 wl_event_loop_add_fd(loop, ec->tty_fd,
521                                      WL_EVENT_READABLE, on_tty_input, ec);
522
523         ec->vt_active = 1;
524         mode.mode = VT_PROCESS;
525         mode.relsig = SIGUSR1;
526         mode.acqsig = SIGUSR2;
527         if (!ioctl(ec->tty_fd, VT_SETMODE, &mode) < 0) {
528                 fprintf(stderr, "failed to take control of vt handling\n");
529         }
530
531         ec->leave_vt_source =
532                 wl_event_loop_add_signal(loop, SIGUSR1, on_leave_vt, ec);
533         ec->enter_vt_source =
534                 wl_event_loop_add_signal(loop, SIGUSR2, on_enter_vt, ec);
535
536         return 0;
537 }
538
539 int
540 wlsc_compositor_init_drm(struct wlsc_compositor *ec)
541 {
542         struct udev_enumerate *e;
543         struct udev_list_entry *entry;
544         struct udev_device *device;
545         const char *path;
546         struct wlsc_input_device *input_device;
547         struct wl_event_loop *loop;
548
549         ec->udev = udev_new();
550         if (ec->udev == NULL) {
551                 fprintf(stderr, "failed to initialize udev context\n");
552                 return -1;
553         }
554
555         input_device = wlsc_input_device_create(ec);
556         ec->input_device = input_device;
557
558         e = udev_enumerate_new(ec->udev);
559         udev_enumerate_add_match_subsystem(e, "input");
560         udev_enumerate_add_match_property(e, "WAYLAND_SEAT", "1");
561         udev_enumerate_scan_devices(e);
562         udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
563                 path = udev_list_entry_get_name(entry);
564                 device = udev_device_new_from_syspath(ec->udev, path);
565                 evdev_input_device_create(input_device, ec->wl_display,
566                                           udev_device_get_devnode(device));
567         }
568         udev_enumerate_unref(e);
569
570         e = udev_enumerate_new(ec->udev);
571         udev_enumerate_add_match_subsystem(e, "drm");
572         udev_enumerate_add_match_property(e, "WAYLAND_SEAT", "1");
573         udev_enumerate_scan_devices(e);
574         udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
575                 path = udev_list_entry_get_name(entry);
576                 device = udev_device_new_from_syspath(ec->udev, path);
577                 fprintf(stderr, "creating output for %s\n", path);
578
579                 if (init_egl(ec, device) < 0) {
580                         fprintf(stderr, "failed to initialize egl\n");
581                         return -1;
582                 }
583                 if (create_outputs(ec) < 0) {
584                         fprintf(stderr, "failed to create output for %s\n", path);
585                         return -1;
586                 }
587         }
588         udev_enumerate_unref(e);
589
590         loop = wl_display_get_event_loop(ec->wl_display);
591         setup_tty(ec, loop);
592
593         return 0;
594 }