downstream: terminal: destroy display at the end.
[profile/ivi/weston-ivi-shell.git] / src / compositor-fbdev.c
1 /*
2  * Copyright © 2008-2011 Kristian Høgsberg
3  * Copyright © 2011 Intel Corporation
4  * Copyright © 2012 Raspberry Pi Foundation
5  * Copyright © 2013 Philip Withnall
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and
8  * its documentation for any purpose is hereby granted without fee, provided
9  * that the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation, and that the name of the copyright holders not be used in
12  * advertising or publicity pertaining to distribution of the software
13  * without specific, written prior permission.  The copyright holders make
14  * no representations about the suitability of this software for any
15  * purpose.  It is provided "as is" without express or implied warranty.
16  *
17  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
18  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
19  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
21  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
22  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24  */
25
26 #include "config.h"
27
28 #include <errno.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <math.h>
33 #include <sys/mman.h>
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <linux/fb.h>
38 #include <linux/input.h>
39
40 #include <libudev.h>
41
42 #include "compositor.h"
43 #include "launcher-util.h"
44 #include "pixman-renderer.h"
45 #include "udev-input.h"
46 #include "gl-renderer.h"
47
48 struct fbdev_compositor {
49         struct weston_compositor base;
50         uint32_t prev_state;
51
52         struct udev *udev;
53         struct udev_input input;
54         int use_pixman;
55         struct wl_listener session_listener;
56 };
57
58 struct fbdev_screeninfo {
59         unsigned int x_resolution; /* pixels, visible area */
60         unsigned int y_resolution; /* pixels, visible area */
61         unsigned int width_mm; /* visible screen width in mm */
62         unsigned int height_mm; /* visible screen height in mm */
63         unsigned int bits_per_pixel;
64
65         size_t buffer_length; /* length of frame buffer memory in bytes */
66         size_t line_length; /* length of a line in bytes */
67         char id[16]; /* screen identifier */
68
69         pixman_format_code_t pixel_format; /* frame buffer pixel format */
70         unsigned int refresh_rate; /* Hertz */
71 };
72
73 struct fbdev_output {
74         struct fbdev_compositor *compositor;
75         struct weston_output base;
76
77         struct weston_mode mode;
78         struct wl_event_source *finish_frame_timer;
79
80         /* Frame buffer details. */
81         const char *device; /* ownership shared with fbdev_parameters */
82         struct fbdev_screeninfo fb_info;
83         void *fb; /* length is fb_info.buffer_length */
84
85         /* pixman details. */
86         pixman_image_t *hw_surface;
87         pixman_image_t *shadow_surface;
88         void *shadow_buf;
89         uint8_t depth;
90 };
91
92 struct fbdev_parameters {
93         int tty;
94         char *device;
95         int use_gl;
96 };
97
98 struct gl_renderer_interface *gl_renderer;
99
100 static const char default_seat[] = "seat0";
101
102 static inline struct fbdev_output *
103 to_fbdev_output(struct weston_output *base)
104 {
105         return container_of(base, struct fbdev_output, base);
106 }
107
108 static inline struct fbdev_compositor *
109 to_fbdev_compositor(struct weston_compositor *base)
110 {
111         return container_of(base, struct fbdev_compositor, base);
112 }
113
114 static void
115 fbdev_output_start_repaint_loop(struct weston_output *output)
116 {
117         uint32_t msec;
118         struct timeval tv;
119
120         gettimeofday(&tv, NULL);
121         msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
122         weston_output_finish_frame(output, msec);
123 }
124
125 static void
126 fbdev_output_repaint_pixman(struct weston_output *base, pixman_region32_t *damage)
127 {
128         struct fbdev_output *output = to_fbdev_output(base);
129         struct weston_compositor *ec = output->base.compositor;
130         pixman_box32_t *rects;
131         int nrects, i, src_x, src_y, x1, y1, x2, y2, width, height;
132
133         /* Repaint the damaged region onto the back buffer. */
134         pixman_renderer_output_set_buffer(base, output->shadow_surface);
135         ec->renderer->repaint_output(base, damage);
136
137         /* Transform and composite onto the frame buffer. */
138         width = pixman_image_get_width(output->shadow_surface);
139         height = pixman_image_get_height(output->shadow_surface);
140         rects = pixman_region32_rectangles(damage, &nrects);
141
142         for (i = 0; i < nrects; i++) {
143                 switch (base->transform) {
144                 default:
145                 case WL_OUTPUT_TRANSFORM_NORMAL:
146                         x1 = rects[i].x1;
147                         x2 = rects[i].x2;
148                         y1 = rects[i].y1;
149                         y2 = rects[i].y2;
150                         break;
151                 case WL_OUTPUT_TRANSFORM_180:
152                         x1 = width - rects[i].x2;
153                         x2 = width - rects[i].x1;
154                         y1 = height - rects[i].y2;
155                         y2 = height - rects[i].y1;
156                         break;
157                 case WL_OUTPUT_TRANSFORM_90:
158                         x1 = height - rects[i].y2;
159                         x2 = height - rects[i].y1;
160                         y1 = rects[i].x1;
161                         y2 = rects[i].x2;
162                         break;
163                 case WL_OUTPUT_TRANSFORM_270:
164                         x1 = rects[i].y1;
165                         x2 = rects[i].y2;
166                         y1 = width - rects[i].x2;
167                         y2 = width - rects[i].x1;
168                         break;
169                 }
170                 src_x = x1;
171                 src_y = y1;
172
173                 pixman_image_composite32(PIXMAN_OP_SRC,
174                         output->shadow_surface, /* src */
175                         NULL /* mask */,
176                         output->hw_surface, /* dest */
177                         src_x, src_y, /* src_x, src_y */
178                         0, 0, /* mask_x, mask_y */
179                         x1, y1, /* dest_x, dest_y */
180                         x2 - x1, /* width */
181                         y2 - y1 /* height */);
182         }
183
184         /* Update the damage region. */
185         pixman_region32_subtract(&ec->primary_plane.damage,
186                                  &ec->primary_plane.damage, damage);
187
188         /* Schedule the end of the frame. We do not sync this to the frame
189          * buffer clock because users who want that should be using the DRM
190          * compositor. FBIO_WAITFORVSYNC blocks and FB_ACTIVATE_VBL requires
191          * panning, which is broken in most kernel drivers.
192          *
193          * Finish the frame synchronised to the specified refresh rate. The
194          * refresh rate is given in mHz and the interval in ms. */
195         wl_event_source_timer_update(output->finish_frame_timer,
196                                      1000000 / output->mode.refresh);
197 }
198
199 static int
200 fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage)
201 {
202         struct fbdev_output *output = to_fbdev_output(base);
203         struct fbdev_compositor *fbc = output->compositor;
204         struct weston_compositor *ec = & fbc->base;
205
206         if (fbc->use_pixman) {
207                 fbdev_output_repaint_pixman(base,damage);
208         } else {
209                 ec->renderer->repaint_output(base, damage);
210                 /* Update the damage region. */
211                 pixman_region32_subtract(&ec->primary_plane.damage,
212                                  &ec->primary_plane.damage, damage);
213
214                 wl_event_source_timer_update(output->finish_frame_timer,
215                                      1000000 / output->mode.refresh);
216         }
217
218         return 0;
219 }
220
221 static int
222 finish_frame_handler(void *data)
223 {
224         struct fbdev_output *output = data;
225
226         fbdev_output_start_repaint_loop(&output->base);
227
228         return 1;
229 }
230
231 static pixman_format_code_t
232 calculate_pixman_format(struct fb_var_screeninfo *vinfo,
233                         struct fb_fix_screeninfo *finfo)
234 {
235         /* Calculate the pixman format supported by the frame buffer from the
236          * buffer's metadata. Return 0 if no known pixman format is supported
237          * (since this has depth 0 it's guaranteed to not conflict with any
238          * actual pixman format).
239          *
240          * Documentation on the vinfo and finfo structures:
241          *    http://www.mjmwired.net/kernel/Documentation/fb/api.txt
242          *
243          * TODO: Try a bit harder to support other formats, including setting
244          * the preferred format in the hardware. */
245         int type;
246
247         weston_log("Calculating pixman format from:\n"
248                    STAMP_SPACE " - type: %i (aux: %i)\n"
249                    STAMP_SPACE " - visual: %i\n"
250                    STAMP_SPACE " - bpp: %i (grayscale: %i)\n"
251                    STAMP_SPACE " - red: offset: %i, length: %i, MSB: %i\n"
252                    STAMP_SPACE " - green: offset: %i, length: %i, MSB: %i\n"
253                    STAMP_SPACE " - blue: offset: %i, length: %i, MSB: %i\n"
254                    STAMP_SPACE " - transp: offset: %i, length: %i, MSB: %i\n",
255                    finfo->type, finfo->type_aux, finfo->visual,
256                    vinfo->bits_per_pixel, vinfo->grayscale,
257                    vinfo->red.offset, vinfo->red.length, vinfo->red.msb_right,
258                    vinfo->green.offset, vinfo->green.length,
259                    vinfo->green.msb_right,
260                    vinfo->blue.offset, vinfo->blue.length,
261                    vinfo->blue.msb_right,
262                    vinfo->transp.offset, vinfo->transp.length,
263                    vinfo->transp.msb_right);
264
265         /* We only handle packed formats at the moment. */
266         if (finfo->type != FB_TYPE_PACKED_PIXELS)
267                 return 0;
268
269         /* We only handle true-colour frame buffers at the moment. */
270         switch(finfo->visual) {
271                 case FB_VISUAL_TRUECOLOR:
272                 case FB_VISUAL_DIRECTCOLOR:
273                         if (vinfo->grayscale != 0)
274                                 return 0;
275                 break;
276                 default:
277                         return 0;
278         }
279
280         /* We only support formats with MSBs on the left. */
281         if (vinfo->red.msb_right != 0 || vinfo->green.msb_right != 0 ||
282             vinfo->blue.msb_right != 0)
283                 return 0;
284
285         /* Work out the format type from the offsets. We only support RGBA and
286          * ARGB at the moment. */
287         type = PIXMAN_TYPE_OTHER;
288
289         if ((vinfo->transp.offset >= vinfo->red.offset ||
290              vinfo->transp.length == 0) &&
291             vinfo->red.offset >= vinfo->green.offset &&
292             vinfo->green.offset >= vinfo->blue.offset)
293                 type = PIXMAN_TYPE_ARGB;
294         else if (vinfo->red.offset >= vinfo->green.offset &&
295                  vinfo->green.offset >= vinfo->blue.offset &&
296                  vinfo->blue.offset >= vinfo->transp.offset)
297                 type = PIXMAN_TYPE_RGBA;
298
299         if (type == PIXMAN_TYPE_OTHER)
300                 return 0;
301
302         /* Build the format. */
303         return PIXMAN_FORMAT(vinfo->bits_per_pixel, type,
304                              vinfo->transp.length,
305                              vinfo->red.length,
306                              vinfo->green.length,
307                              vinfo->blue.length);
308 }
309
310 static int
311 calculate_refresh_rate(struct fb_var_screeninfo *vinfo)
312 {
313         uint64_t quot;
314
315         /* Calculate monitor refresh rate. Default is 60 Hz. Units are mHz. */
316         quot = (vinfo->upper_margin + vinfo->lower_margin + vinfo->yres);
317         quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres);
318         quot *= vinfo->pixclock;
319
320         if (quot > 0) {
321                 uint64_t refresh_rate;
322
323                 refresh_rate = 1000000000000000LLU / quot;
324                 if (refresh_rate > 200000)
325                         refresh_rate = 200000; /* cap at 200 Hz */
326
327                 return refresh_rate;
328         }
329
330         return 60 * 1000; /* default to 60 Hz */
331 }
332
333 static int
334 fbdev_query_screen_info(struct fbdev_output *output, int fd,
335                         struct fbdev_screeninfo *info)
336 {
337         struct fb_var_screeninfo varinfo;
338         struct fb_fix_screeninfo fixinfo;
339
340         /* Probe the device for screen information. */
341         if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) < 0 ||
342             ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
343                 return -1;
344         }
345
346         /* Store the pertinent data. */
347         info->x_resolution = varinfo.xres;
348         info->y_resolution = varinfo.yres;
349         info->width_mm = varinfo.width;
350         info->height_mm = varinfo.height;
351         info->bits_per_pixel = varinfo.bits_per_pixel;
352
353         info->buffer_length = fixinfo.smem_len;
354         info->line_length = fixinfo.line_length;
355         strncpy(info->id, fixinfo.id, sizeof(info->id) / sizeof(*info->id));
356
357         info->pixel_format = calculate_pixman_format(&varinfo, &fixinfo);
358         info->refresh_rate = calculate_refresh_rate(&varinfo);
359
360         if (info->pixel_format == 0) {
361                 weston_log("Frame buffer uses an unsupported format.\n");
362                 return -1;
363         }
364
365         return 1;
366 }
367
368 static int
369 fbdev_set_screen_info(struct fbdev_output *output, int fd,
370                       struct fbdev_screeninfo *info)
371 {
372         struct fb_var_screeninfo varinfo;
373
374         /* Grab the current screen information. */
375         if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
376                 return -1;
377         }
378
379         /* Update the information. */
380         varinfo.xres = info->x_resolution;
381         varinfo.yres = info->y_resolution;
382         varinfo.width = info->width_mm;
383         varinfo.height = info->height_mm;
384         varinfo.bits_per_pixel = info->bits_per_pixel;
385
386         /* Try to set up an ARGB (x8r8g8b8) pixel format. */
387         varinfo.grayscale = 0;
388         varinfo.transp.offset = 24;
389         varinfo.transp.length = 0;
390         varinfo.transp.msb_right = 0;
391         varinfo.red.offset = 16;
392         varinfo.red.length = 8;
393         varinfo.red.msb_right = 0;
394         varinfo.green.offset = 8;
395         varinfo.green.length = 8;
396         varinfo.green.msb_right = 0;
397         varinfo.blue.offset = 0;
398         varinfo.blue.length = 8;
399         varinfo.blue.msb_right = 0;
400
401         /* Set the device's screen information. */
402         if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
403                 return -1;
404         }
405
406         return 1;
407 }
408
409 static void fbdev_frame_buffer_destroy(struct fbdev_output *output);
410
411 /* Returns an FD for the frame buffer device. */
412 static int
413 fbdev_frame_buffer_open(struct fbdev_output *output, const char *fb_dev,
414                         struct fbdev_screeninfo *screen_info)
415 {
416         int fd = -1;
417
418         weston_log("Opening fbdev frame buffer.\n");
419
420         /* Open the frame buffer device. */
421         fd = open(fb_dev, O_RDWR | O_CLOEXEC);
422         if (fd < 0) {
423                 weston_log("Failed to open frame buffer device ‘%s’: %s\n",
424                            fb_dev, strerror(errno));
425                 return -1;
426         }
427
428         /* Grab the screen info. */
429         if (fbdev_query_screen_info(output, fd, screen_info) < 0) {
430                 weston_log("Failed to get frame buffer info: %s\n",
431                            strerror(errno));
432
433                 close(fd);
434                 return -1;
435         }
436
437         return fd;
438 }
439
440 /* Closes the FD on success or failure. */
441 static int
442 fbdev_frame_buffer_map(struct fbdev_output *output, int fd)
443 {
444         int retval = -1;
445
446         weston_log("Mapping fbdev frame buffer.\n");
447
448         /* Map the frame buffer. Write-only mode, since we don't want to read
449          * anything back (because it's slow). */
450         output->fb = mmap(NULL, output->fb_info.buffer_length,
451                           PROT_WRITE, MAP_SHARED, fd, 0);
452         if (output->fb == MAP_FAILED) {
453                 weston_log("Failed to mmap frame buffer: %s\n",
454                            strerror(errno));
455                 goto out_close;
456         }
457
458         /* Create a pixman image to wrap the memory mapped frame buffer. */
459         output->hw_surface =
460                 pixman_image_create_bits(output->fb_info.pixel_format,
461                                          output->fb_info.x_resolution,
462                                          output->fb_info.y_resolution,
463                                          output->fb,
464                                          output->fb_info.line_length);
465         if (output->hw_surface == NULL) {
466                 weston_log("Failed to create surface for frame buffer.\n");
467                 goto out_unmap;
468         }
469
470         /* Success! */
471         retval = 0;
472
473 out_unmap:
474         if (retval != 0 && output->fb != NULL)
475                 fbdev_frame_buffer_destroy(output);
476
477 out_close:
478         if (fd >= 0)
479                 close(fd);
480
481         return retval;
482 }
483
484 static void
485 fbdev_frame_buffer_destroy(struct fbdev_output *output)
486 {
487         weston_log("Destroying fbdev frame buffer.\n");
488
489         if (munmap(output->fb, output->fb_info.buffer_length) < 0)
490                 weston_log("Failed to munmap frame buffer: %s\n",
491                            strerror(errno));
492
493         output->fb = NULL;
494 }
495
496 static void fbdev_output_destroy(struct weston_output *base);
497 static void fbdev_output_disable(struct weston_output *base);
498
499 static int
500 fbdev_output_create(struct fbdev_compositor *compositor,
501                     const char *device)
502 {
503         struct fbdev_output *output;
504         pixman_transform_t transform;
505         int fb_fd;
506         int shadow_width, shadow_height;
507         int width, height;
508         unsigned int bytes_per_pixel;
509         struct wl_event_loop *loop;
510
511         weston_log("Creating fbdev output.\n");
512
513         output = calloc(1, sizeof *output);
514         if (!output)
515                 return -1;
516
517         output->compositor = compositor;
518         output->device = device;
519
520         /* Create the frame buffer. */
521         fb_fd = fbdev_frame_buffer_open(output, device, &output->fb_info);
522         if (fb_fd < 0) {
523                 weston_log("Creating frame buffer failed.\n");
524                 goto out_free;
525         }
526         if (compositor->use_pixman) {
527                 if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
528                         weston_log("Mapping frame buffer failed.\n");
529                         goto out_free;
530                 }
531         } else {
532                 close(fb_fd);
533         }
534
535         output->base.start_repaint_loop = fbdev_output_start_repaint_loop;
536         output->base.repaint = fbdev_output_repaint;
537         output->base.destroy = fbdev_output_destroy;
538         output->base.assign_planes = NULL;
539         output->base.set_backlight = NULL;
540         output->base.set_dpms = NULL;
541         output->base.switch_mode = NULL;
542
543         /* only one static mode in list */
544         output->mode.flags =
545                 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
546         output->mode.width = output->fb_info.x_resolution;
547         output->mode.height = output->fb_info.y_resolution;
548         output->mode.refresh = output->fb_info.refresh_rate;
549         wl_list_init(&output->base.mode_list);
550         wl_list_insert(&output->base.mode_list, &output->mode.link);
551
552         output->base.current_mode = &output->mode;
553         output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
554         output->base.make = "unknown";
555         output->base.model = output->fb_info.id;
556
557         weston_output_init(&output->base, &compositor->base,
558                            0, 0, output->fb_info.width_mm,
559                            output->fb_info.height_mm,
560                            WL_OUTPUT_TRANSFORM_NORMAL,
561                            1);
562
563         width = output->fb_info.x_resolution;
564         height = output->fb_info.y_resolution;
565
566         pixman_transform_init_identity(&transform);
567         switch (output->base.transform) {
568         default:
569         case WL_OUTPUT_TRANSFORM_NORMAL:
570                 shadow_width = width;
571                 shadow_height = height;
572                 pixman_transform_rotate(&transform,
573                         NULL, 0, 0);
574                 pixman_transform_translate(&transform, NULL,
575                         0, 0);
576                 break;
577         case WL_OUTPUT_TRANSFORM_180:
578                 shadow_width = width;
579                 shadow_height = height;
580                 pixman_transform_rotate(&transform,
581                         NULL, -pixman_fixed_1, 0);
582                 pixman_transform_translate(NULL, &transform,
583                         pixman_int_to_fixed(shadow_width),
584                         pixman_int_to_fixed(shadow_height));
585                 break;
586         case WL_OUTPUT_TRANSFORM_270:
587                 shadow_width = height;
588                 shadow_height = width;
589                 pixman_transform_rotate(&transform,
590                         NULL, 0, pixman_fixed_1);
591                 pixman_transform_translate(&transform,
592                         NULL,
593                         pixman_int_to_fixed(shadow_width),
594                         0);
595                 break;
596         case WL_OUTPUT_TRANSFORM_90:
597                 shadow_width = height;
598                 shadow_height = width;
599                 pixman_transform_rotate(&transform,
600                         NULL, 0, -pixman_fixed_1);
601                 pixman_transform_translate(&transform,
602                         NULL,
603                         0,
604                         pixman_int_to_fixed(shadow_height));
605                 break;
606         }
607
608         bytes_per_pixel = output->fb_info.bits_per_pixel / 8;
609
610         output->shadow_buf = malloc(width * height * bytes_per_pixel);
611         output->shadow_surface =
612                 pixman_image_create_bits(output->fb_info.pixel_format,
613                                          shadow_width, shadow_height,
614                                          output->shadow_buf,
615                                          shadow_width * bytes_per_pixel);
616         if (output->shadow_buf == NULL || output->shadow_surface == NULL) {
617                 weston_log("Failed to create surface for frame buffer.\n");
618                 goto out_hw_surface;
619         }
620
621         /* No need in transform for normal output */
622         if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
623                 pixman_image_set_transform(output->shadow_surface, &transform);
624
625         if (compositor->use_pixman) {
626                 if (pixman_renderer_output_create(&output->base) < 0)
627                         goto out_shadow_surface;
628         } else {
629                 setenv("HYBRIS_EGLPLATFORM", "wayland", 1);
630                 if (gl_renderer->output_create(&output->base,
631                                                (EGLNativeWindowType)NULL,
632                                                gl_renderer->opaque_attribs,
633                                                NULL) < 0) {
634                         weston_log("gl_renderer_output_create failed.\n");
635                         goto out_shadow_surface;
636                 }
637         }
638
639
640         loop = wl_display_get_event_loop(compositor->base.wl_display);
641         output->finish_frame_timer =
642                 wl_event_loop_add_timer(loop, finish_frame_handler, output);
643
644         wl_list_insert(compositor->base.output_list.prev, &output->base.link);
645
646         weston_log("fbdev output %d×%d px\n",
647                    output->mode.width, output->mode.height);
648         weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
649                             output->mode.refresh / 1000);
650
651         return 0;
652
653 out_shadow_surface:
654         pixman_image_unref(output->shadow_surface);
655         output->shadow_surface = NULL;
656 out_hw_surface:
657         free(output->shadow_buf);
658         pixman_image_unref(output->hw_surface);
659         output->hw_surface = NULL;
660         weston_output_destroy(&output->base);
661         fbdev_frame_buffer_destroy(output);
662 out_free:
663         free(output);
664
665         return -1;
666 }
667
668 static void
669 fbdev_output_destroy(struct weston_output *base)
670 {
671         struct fbdev_output *output = to_fbdev_output(base);
672         struct fbdev_compositor *compositor = output->compositor;
673
674         weston_log("Destroying fbdev output.\n");
675
676         /* Close the frame buffer. */
677         fbdev_output_disable(base);
678
679         if (compositor->use_pixman) {
680                 if (base->renderer_state != NULL)
681                         pixman_renderer_output_destroy(base);
682
683                 if (output->shadow_surface != NULL) {
684                         pixman_image_unref(output->shadow_surface);
685                         output->shadow_surface = NULL;
686                 }
687
688                 if (output->shadow_buf != NULL) {
689                         free(output->shadow_buf);
690                         output->shadow_buf = NULL;
691                 }
692         } else {
693                 gl_renderer->output_destroy(base);
694         }
695
696         /* Remove the output. */
697         weston_output_destroy(&output->base);
698
699         free(output);
700 }
701
702 /* strcmp()-style return values. */
703 static int
704 compare_screen_info (const struct fbdev_screeninfo *a,
705                      const struct fbdev_screeninfo *b)
706 {
707         if (a->x_resolution == b->x_resolution &&
708             a->y_resolution == b->y_resolution &&
709             a->width_mm == b->width_mm &&
710             a->height_mm == b->height_mm &&
711             a->bits_per_pixel == b->bits_per_pixel &&
712             a->pixel_format == b->pixel_format &&
713             a->refresh_rate == b->refresh_rate)
714                 return 0;
715
716         return 1;
717 }
718
719 static int
720 fbdev_output_reenable(struct fbdev_compositor *compositor,
721                       struct weston_output *base)
722 {
723         struct fbdev_output *output = to_fbdev_output(base);
724         struct fbdev_screeninfo new_screen_info;
725         int fb_fd;
726         const char *device;
727
728         weston_log("Re-enabling fbdev output.\n");
729
730         /* Create the frame buffer. */
731         fb_fd = fbdev_frame_buffer_open(output, output->device,
732                                         &new_screen_info);
733         if (fb_fd < 0) {
734                 weston_log("Creating frame buffer failed.\n");
735                 goto err;
736         }
737
738         /* Check whether the frame buffer details have changed since we were
739          * disabled. */
740         if (compare_screen_info (&output->fb_info, &new_screen_info) != 0) {
741                 /* Perform a mode-set to restore the old mode. */
742                 if (fbdev_set_screen_info(output, fb_fd,
743                                           &output->fb_info) < 0) {
744                         weston_log("Failed to restore mode settings. "
745                                    "Attempting to re-open output anyway.\n");
746                 }
747
748                 close(fb_fd);
749
750                 /* Remove and re-add the output so that resources depending on
751                  * the frame buffer X/Y resolution (such as the shadow buffer)
752                  * are re-initialised. */
753                 device = output->device;
754                 fbdev_output_destroy(base);
755                 fbdev_output_create(compositor, device);
756
757                 return 0;
758         }
759
760         /* Map the device if it has the same details as before. */
761         if (compositor->use_pixman) {
762                 if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
763                         weston_log("Mapping frame buffer failed.\n");
764                         goto err;
765                 }
766         }
767
768         return 0;
769
770 err:
771         return -1;
772 }
773
774 /* NOTE: This leaves output->fb_info populated, caching data so that if
775  * fbdev_output_reenable() is called again, it can determine whether a mode-set
776  * is needed. */
777 static void
778 fbdev_output_disable(struct weston_output *base)
779 {
780         struct fbdev_output *output = to_fbdev_output(base);
781         struct fbdev_compositor *compositor = output->compositor;
782
783         weston_log("Disabling fbdev output.\n");
784
785         if ( ! compositor->use_pixman) return;
786
787         if (output->hw_surface != NULL) {
788                 pixman_image_unref(output->hw_surface);
789                 output->hw_surface = NULL;
790         }
791
792         fbdev_frame_buffer_destroy(output);
793 }
794
795 static void
796 fbdev_compositor_destroy(struct weston_compositor *base)
797 {
798         struct fbdev_compositor *compositor = to_fbdev_compositor(base);
799
800         udev_input_destroy(&compositor->input);
801
802         /* Destroy the output. */
803         weston_compositor_shutdown(&compositor->base);
804
805         /* Chain up. */
806         weston_launcher_destroy(compositor->base.launcher);
807
808         free(compositor);
809 }
810
811 static void
812 session_notify(struct wl_listener *listener, void *data)
813 {
814         struct fbdev_compositor *compositor = data;
815         struct weston_output *output;
816
817         if (compositor->base.session_active) {
818                 weston_log("entering VT\n");
819                 compositor->base.state = compositor->prev_state;
820
821                 wl_list_for_each(output, &compositor->base.output_list, link) {
822                         fbdev_output_reenable(compositor, output);
823                 }
824
825                 weston_compositor_damage_all(&compositor->base);
826
827                 udev_input_enable(&compositor->input);
828         } else {
829                 weston_log("leaving VT\n");
830                 udev_input_disable(&compositor->input);
831
832                 wl_list_for_each(output, &compositor->base.output_list, link) {
833                         fbdev_output_disable(output);
834                 }
835
836                 compositor->prev_state = compositor->base.state;
837                 weston_compositor_offscreen(&compositor->base);
838
839                 /* If we have a repaint scheduled (from the idle handler), make
840                  * sure we cancel that so we don't try to pageflip when we're
841                  * vt switched away.  The OFFSCREEN state will prevent
842                  * further attemps at repainting.  When we switch
843                  * back, we schedule a repaint, which will process
844                  * pending frame callbacks. */
845
846                 wl_list_for_each(output,
847                                  &compositor->base.output_list, link) {
848                         output->repaint_needed = 0;
849                 }
850         };
851 }
852
853 static void
854 fbdev_restore(struct weston_compositor *compositor)
855 {
856         weston_launcher_restore(compositor->launcher);
857 }
858
859 static void
860 switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
861 {
862         struct weston_compositor *compositor = data;
863
864         weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
865 }
866
867 static struct weston_compositor *
868 fbdev_compositor_create(struct wl_display *display, int *argc, char *argv[],
869                         struct weston_config *config,
870                         struct fbdev_parameters *param)
871 {
872         struct fbdev_compositor *compositor;
873         const char *seat_id = default_seat;
874         uint32_t key;
875
876         weston_log("initializing fbdev backend\n");
877
878         compositor = calloc(1, sizeof *compositor);
879         if (compositor == NULL)
880                 return NULL;
881
882         if (weston_compositor_init(&compositor->base, display, argc, argv,
883                                    config) < 0)
884                 goto out_free;
885
886         compositor->udev = udev_new();
887         if (compositor->udev == NULL) {
888                 weston_log("Failed to initialize udev context.\n");
889                 goto out_compositor;
890         }
891
892         /* Set up the TTY. */
893         compositor->session_listener.notify = session_notify;
894         wl_signal_add(&compositor->base.session_signal,
895                       &compositor->session_listener);
896         compositor->base.launcher =
897                 weston_launcher_connect(&compositor->base, param->tty, "seat0");
898         if (!compositor->base.launcher) {
899                 weston_log("fatal: fbdev backend should be run "
900                            "using weston-launch binary or as root\n");
901                 goto out_udev;
902         }
903
904         compositor->base.destroy = fbdev_compositor_destroy;
905         compositor->base.restore = fbdev_restore;
906
907         compositor->prev_state = WESTON_COMPOSITOR_ACTIVE;
908         compositor->use_pixman = !param->use_gl;
909
910         for (key = KEY_F1; key < KEY_F9; key++)
911                 weston_compositor_add_key_binding(&compositor->base, key,
912                                                   MODIFIER_CTRL | MODIFIER_ALT,
913                                                   switch_vt_binding,
914                                                   compositor);
915         if (compositor->use_pixman) {
916                 if (pixman_renderer_init(&compositor->base) < 0)
917                         goto out_launcher;
918         } else {
919                 gl_renderer = weston_load_module("gl-renderer.so",
920                                                  "gl_renderer_interface");
921                 if (!gl_renderer) {
922                         weston_log("could not load gl renderer\n");
923                         goto out_launcher;
924                 }
925
926                 if (gl_renderer->create(&compositor->base, EGL_DEFAULT_DISPLAY,
927                                         gl_renderer->opaque_attribs,
928                                         NULL) < 0) {
929                         weston_log("gl_renderer_create failed.\n");
930                         goto out_launcher;
931                 }
932         }
933
934         if (fbdev_output_create(compositor, param->device) < 0)
935                 goto out_pixman;
936
937         udev_input_init(&compositor->input, &compositor->base, compositor->udev, seat_id);
938
939         return &compositor->base;
940
941 out_pixman:
942         compositor->base.renderer->destroy(&compositor->base);
943
944 out_launcher:
945         weston_launcher_destroy(compositor->base.launcher);
946
947 out_udev:
948         udev_unref(compositor->udev);
949
950 out_compositor:
951         weston_compositor_shutdown(&compositor->base);
952
953 out_free:
954         free(compositor);
955
956         return NULL;
957 }
958
959 WL_EXPORT struct weston_compositor *
960 backend_init(struct wl_display *display, int *argc, char *argv[],
961              struct weston_config *config)
962 {
963         /* TODO: Ideally, available frame buffers should be enumerated using
964          * udev, rather than passing a device node in as a parameter. */
965         struct fbdev_parameters param = {
966                 .tty = 0, /* default to current tty */
967                 .device = "/dev/fb0", /* default frame buffer */
968                 .use_gl = 0,
969         };
970
971         const struct weston_option fbdev_options[] = {
972                 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
973                 { WESTON_OPTION_STRING, "device", 0, &param.device },
974                 { WESTON_OPTION_BOOLEAN, "use-gl", 0, &param.use_gl },
975         };
976
977         parse_options(fbdev_options, ARRAY_LENGTH(fbdev_options), argc, argv);
978
979         return fbdev_compositor_create(display, argc, argv, config, &param);
980 }