2 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
4 * Copyright © 2012 Raspberry Pi Foundation
5 * Copyright © 2013 Philip Withnall
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial
17 * portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38 #include <sys/types.h>
42 #include <linux/input.h>
46 #include "shared/helpers.h"
47 #include "compositor.h"
48 #include "compositor-fbdev.h"
49 #include "launcher-util.h"
50 #include "pixman-renderer.h"
51 #include "libinput-seat.h"
52 #include "presentation-time-server-protocol.h"
54 struct fbdev_backend {
55 struct weston_backend base;
56 struct weston_compositor *compositor;
60 struct udev_input input;
61 uint32_t output_transform;
62 struct wl_listener session_listener;
65 struct fbdev_screeninfo {
66 unsigned int x_resolution; /* pixels, visible area */
67 unsigned int y_resolution; /* pixels, visible area */
68 unsigned int width_mm; /* visible screen width in mm */
69 unsigned int height_mm; /* visible screen height in mm */
70 unsigned int bits_per_pixel;
72 size_t buffer_length; /* length of frame buffer memory in bytes */
73 size_t line_length; /* length of a line in bytes */
74 char id[16]; /* screen identifier */
76 pixman_format_code_t pixel_format; /* frame buffer pixel format */
77 unsigned int refresh_rate; /* Hertz */
81 struct fbdev_backend *backend;
82 struct weston_output base;
84 struct weston_mode mode;
85 struct wl_event_source *finish_frame_timer;
87 /* Frame buffer details. */
89 struct fbdev_screeninfo fb_info;
90 void *fb; /* length is fb_info.buffer_length */
93 pixman_image_t *hw_surface;
97 static const char default_seat[] = "seat0";
99 static inline struct fbdev_output *
100 to_fbdev_output(struct weston_output *base)
102 return container_of(base, struct fbdev_output, base);
105 static inline struct fbdev_backend *
106 to_fbdev_backend(struct weston_compositor *base)
108 return container_of(base->backend, struct fbdev_backend, base);
112 fbdev_output_start_repaint_loop(struct weston_output *output)
116 weston_compositor_read_presentation_clock(output->compositor, &ts);
117 weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
121 fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage)
123 struct fbdev_output *output = to_fbdev_output(base);
124 struct weston_compositor *ec = output->base.compositor;
126 /* Repaint the damaged region onto the back buffer. */
127 pixman_renderer_output_set_buffer(base, output->hw_surface);
128 ec->renderer->repaint_output(base, damage);
130 /* Update the damage region. */
131 pixman_region32_subtract(&ec->primary_plane.damage,
132 &ec->primary_plane.damage, damage);
134 /* Schedule the end of the frame. We do not sync this to the frame
135 * buffer clock because users who want that should be using the DRM
136 * compositor. FBIO_WAITFORVSYNC blocks and FB_ACTIVATE_VBL requires
137 * panning, which is broken in most kernel drivers.
139 * Finish the frame synchronised to the specified refresh rate. The
140 * refresh rate is given in mHz and the interval in ms. */
141 wl_event_source_timer_update(output->finish_frame_timer,
142 1000000 / output->mode.refresh);
148 finish_frame_handler(void *data)
150 struct fbdev_output *output = data;
153 weston_compositor_read_presentation_clock(output->base.compositor, &ts);
154 weston_output_finish_frame(&output->base, &ts, 0);
159 static pixman_format_code_t
160 calculate_pixman_format(struct fb_var_screeninfo *vinfo,
161 struct fb_fix_screeninfo *finfo)
163 /* Calculate the pixman format supported by the frame buffer from the
164 * buffer's metadata. Return 0 if no known pixman format is supported
165 * (since this has depth 0 it's guaranteed to not conflict with any
166 * actual pixman format).
168 * Documentation on the vinfo and finfo structures:
169 * http://www.mjmwired.net/kernel/Documentation/fb/api.txt
171 * TODO: Try a bit harder to support other formats, including setting
172 * the preferred format in the hardware. */
175 weston_log("Calculating pixman format from:\n"
176 STAMP_SPACE " - type: %i (aux: %i)\n"
177 STAMP_SPACE " - visual: %i\n"
178 STAMP_SPACE " - bpp: %i (grayscale: %i)\n"
179 STAMP_SPACE " - red: offset: %i, length: %i, MSB: %i\n"
180 STAMP_SPACE " - green: offset: %i, length: %i, MSB: %i\n"
181 STAMP_SPACE " - blue: offset: %i, length: %i, MSB: %i\n"
182 STAMP_SPACE " - transp: offset: %i, length: %i, MSB: %i\n",
183 finfo->type, finfo->type_aux, finfo->visual,
184 vinfo->bits_per_pixel, vinfo->grayscale,
185 vinfo->red.offset, vinfo->red.length, vinfo->red.msb_right,
186 vinfo->green.offset, vinfo->green.length,
187 vinfo->green.msb_right,
188 vinfo->blue.offset, vinfo->blue.length,
189 vinfo->blue.msb_right,
190 vinfo->transp.offset, vinfo->transp.length,
191 vinfo->transp.msb_right);
193 /* We only handle packed formats at the moment. */
194 if (finfo->type != FB_TYPE_PACKED_PIXELS)
197 /* We only handle true-colour frame buffers at the moment. */
198 switch(finfo->visual) {
199 case FB_VISUAL_TRUECOLOR:
200 case FB_VISUAL_DIRECTCOLOR:
201 if (vinfo->grayscale != 0)
208 /* We only support formats with MSBs on the left. */
209 if (vinfo->red.msb_right != 0 || vinfo->green.msb_right != 0 ||
210 vinfo->blue.msb_right != 0)
213 /* Work out the format type from the offsets. We only support RGBA and
214 * ARGB at the moment. */
215 type = PIXMAN_TYPE_OTHER;
217 if ((vinfo->transp.offset >= vinfo->red.offset ||
218 vinfo->transp.length == 0) &&
219 vinfo->red.offset >= vinfo->green.offset &&
220 vinfo->green.offset >= vinfo->blue.offset)
221 type = PIXMAN_TYPE_ARGB;
222 else if (vinfo->red.offset >= vinfo->green.offset &&
223 vinfo->green.offset >= vinfo->blue.offset &&
224 vinfo->blue.offset >= vinfo->transp.offset)
225 type = PIXMAN_TYPE_RGBA;
227 if (type == PIXMAN_TYPE_OTHER)
230 /* Build the format. */
231 return PIXMAN_FORMAT(vinfo->bits_per_pixel, type,
232 vinfo->transp.length,
239 calculate_refresh_rate(struct fb_var_screeninfo *vinfo)
243 /* Calculate monitor refresh rate. Default is 60 Hz. Units are mHz. */
244 quot = (vinfo->upper_margin + vinfo->lower_margin + vinfo->yres);
245 quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres);
246 quot *= vinfo->pixclock;
249 uint64_t refresh_rate;
251 refresh_rate = 1000000000000000LLU / quot;
252 if (refresh_rate > 200000)
253 refresh_rate = 200000; /* cap at 200 Hz */
258 return 60 * 1000; /* default to 60 Hz */
262 fbdev_query_screen_info(struct fbdev_output *output, int fd,
263 struct fbdev_screeninfo *info)
265 struct fb_var_screeninfo varinfo;
266 struct fb_fix_screeninfo fixinfo;
268 /* Probe the device for screen information. */
269 if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) < 0 ||
270 ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
274 /* Store the pertinent data. */
275 info->x_resolution = varinfo.xres;
276 info->y_resolution = varinfo.yres;
277 info->width_mm = varinfo.width;
278 info->height_mm = varinfo.height;
279 info->bits_per_pixel = varinfo.bits_per_pixel;
281 info->buffer_length = fixinfo.smem_len;
282 info->line_length = fixinfo.line_length;
283 strncpy(info->id, fixinfo.id, sizeof(info->id));
284 info->id[sizeof(info->id)-1] = '\0';
286 info->pixel_format = calculate_pixman_format(&varinfo, &fixinfo);
287 info->refresh_rate = calculate_refresh_rate(&varinfo);
289 if (info->pixel_format == 0) {
290 weston_log("Frame buffer uses an unsupported format.\n");
298 fbdev_set_screen_info(struct fbdev_output *output, int fd,
299 struct fbdev_screeninfo *info)
301 struct fb_var_screeninfo varinfo;
303 /* Grab the current screen information. */
304 if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
308 /* Update the information. */
309 varinfo.xres = info->x_resolution;
310 varinfo.yres = info->y_resolution;
311 varinfo.width = info->width_mm;
312 varinfo.height = info->height_mm;
313 varinfo.bits_per_pixel = info->bits_per_pixel;
315 /* Try to set up an ARGB (x8r8g8b8) pixel format. */
316 varinfo.grayscale = 0;
317 varinfo.transp.offset = 24;
318 varinfo.transp.length = 0;
319 varinfo.transp.msb_right = 0;
320 varinfo.red.offset = 16;
321 varinfo.red.length = 8;
322 varinfo.red.msb_right = 0;
323 varinfo.green.offset = 8;
324 varinfo.green.length = 8;
325 varinfo.green.msb_right = 0;
326 varinfo.blue.offset = 0;
327 varinfo.blue.length = 8;
328 varinfo.blue.msb_right = 0;
330 /* Set the device's screen information. */
331 if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
338 static void fbdev_frame_buffer_destroy(struct fbdev_output *output);
340 /* Returns an FD for the frame buffer device. */
342 fbdev_frame_buffer_open(struct fbdev_output *output, const char *fb_dev,
343 struct fbdev_screeninfo *screen_info)
347 weston_log("Opening fbdev frame buffer.\n");
349 /* Open the frame buffer device. */
350 fd = open(fb_dev, O_RDWR | O_CLOEXEC);
352 weston_log("Failed to open frame buffer device ‘%s’: %s\n",
353 fb_dev, strerror(errno));
357 /* Grab the screen info. */
358 if (fbdev_query_screen_info(output, fd, screen_info) < 0) {
359 weston_log("Failed to get frame buffer info: %s\n",
369 /* Closes the FD on success or failure. */
371 fbdev_frame_buffer_map(struct fbdev_output *output, int fd)
375 weston_log("Mapping fbdev frame buffer.\n");
377 /* Map the frame buffer. Write-only mode, since we don't want to read
378 * anything back (because it's slow). */
379 output->fb = mmap(NULL, output->fb_info.buffer_length,
380 PROT_WRITE, MAP_SHARED, fd, 0);
381 if (output->fb == MAP_FAILED) {
382 weston_log("Failed to mmap frame buffer: %s\n",
387 /* Create a pixman image to wrap the memory mapped frame buffer. */
389 pixman_image_create_bits(output->fb_info.pixel_format,
390 output->fb_info.x_resolution,
391 output->fb_info.y_resolution,
393 output->fb_info.line_length);
394 if (output->hw_surface == NULL) {
395 weston_log("Failed to create surface for frame buffer.\n");
403 if (retval != 0 && output->fb != NULL)
404 fbdev_frame_buffer_destroy(output);
414 fbdev_frame_buffer_destroy(struct fbdev_output *output)
416 weston_log("Destroying fbdev frame buffer.\n");
418 if (munmap(output->fb, output->fb_info.buffer_length) < 0)
419 weston_log("Failed to munmap frame buffer: %s\n",
425 static void fbdev_output_destroy(struct weston_output *base);
426 static void fbdev_output_disable(struct weston_output *base);
429 fbdev_output_enable(struct weston_output *base)
431 struct fbdev_output *output = to_fbdev_output(base);
432 struct fbdev_backend *backend = to_fbdev_backend(base->compositor);
434 struct wl_event_loop *loop;
436 /* Create the frame buffer. */
437 fb_fd = fbdev_frame_buffer_open(output, output->device, &output->fb_info);
439 weston_log("Creating frame buffer failed.\n");
443 if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
444 weston_log("Mapping frame buffer failed.\n");
448 output->base.start_repaint_loop = fbdev_output_start_repaint_loop;
449 output->base.repaint = fbdev_output_repaint;
451 if (pixman_renderer_output_create(&output->base) < 0)
454 loop = wl_display_get_event_loop(backend->compositor->wl_display);
455 output->finish_frame_timer =
456 wl_event_loop_add_timer(loop, finish_frame_handler, output);
458 weston_log("fbdev output %d×%d px\n",
459 output->mode.width, output->mode.height);
460 weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
461 output->mode.refresh / 1000);
466 pixman_image_unref(output->hw_surface);
467 output->hw_surface = NULL;
468 fbdev_frame_buffer_destroy(output);
474 fbdev_output_create(struct fbdev_backend *backend,
477 struct fbdev_output *output;
480 weston_log("Creating fbdev output.\n");
482 output = zalloc(sizeof *output);
486 output->backend = backend;
487 output->device = strdup(device);
489 /* Create the frame buffer. */
490 fb_fd = fbdev_frame_buffer_open(output, device, &output->fb_info);
492 weston_log("Creating frame buffer failed.\n");
496 output->base.name = strdup("fbdev");
497 output->base.destroy = fbdev_output_destroy;
498 output->base.disable = NULL;
499 output->base.enable = fbdev_output_enable;
501 weston_output_init(&output->base, backend->compositor);
503 /* only one static mode in list */
505 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
506 output->mode.width = output->fb_info.x_resolution;
507 output->mode.height = output->fb_info.y_resolution;
508 output->mode.refresh = output->fb_info.refresh_rate;
509 wl_list_init(&output->base.mode_list);
510 wl_list_insert(&output->base.mode_list, &output->mode.link);
512 output->base.current_mode = &output->mode;
513 output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
514 output->base.make = "unknown";
515 output->base.model = output->fb_info.id;
517 output->base.mm_width = output->fb_info.width_mm;
518 output->base.mm_height = output->fb_info.height_mm;
522 weston_compositor_add_pending_output(&output->base, backend->compositor);
527 free(output->device);
534 fbdev_output_destroy(struct weston_output *base)
536 struct fbdev_output *output = to_fbdev_output(base);
538 weston_log("Destroying fbdev output.\n");
540 /* Close the frame buffer. */
541 fbdev_output_disable(base);
543 if (base->renderer_state != NULL)
544 pixman_renderer_output_destroy(base);
546 /* Remove the output. */
547 weston_output_destroy(&output->base);
549 free(output->device);
553 /* strcmp()-style return values. */
555 compare_screen_info (const struct fbdev_screeninfo *a,
556 const struct fbdev_screeninfo *b)
558 if (a->x_resolution == b->x_resolution &&
559 a->y_resolution == b->y_resolution &&
560 a->width_mm == b->width_mm &&
561 a->height_mm == b->height_mm &&
562 a->bits_per_pixel == b->bits_per_pixel &&
563 a->pixel_format == b->pixel_format &&
564 a->refresh_rate == b->refresh_rate)
571 fbdev_output_reenable(struct fbdev_backend *backend,
572 struct weston_output *base)
574 struct fbdev_output *output = to_fbdev_output(base);
575 struct fbdev_screeninfo new_screen_info;
579 weston_log("Re-enabling fbdev output.\n");
581 /* Create the frame buffer. */
582 fb_fd = fbdev_frame_buffer_open(output, output->device,
585 weston_log("Creating frame buffer failed.\n");
589 /* Check whether the frame buffer details have changed since we were
591 if (compare_screen_info (&output->fb_info, &new_screen_info) != 0) {
592 /* Perform a mode-set to restore the old mode. */
593 if (fbdev_set_screen_info(output, fb_fd,
594 &output->fb_info) < 0) {
595 weston_log("Failed to restore mode settings. "
596 "Attempting to re-open output anyway.\n");
601 /* Remove and re-add the output so that resources depending on
602 * the frame buffer X/Y resolution (such as the shadow buffer)
603 * are re-initialised. */
604 device = strdup(output->device);
605 fbdev_output_destroy(&output->base);
606 fbdev_output_create(backend, device);
612 /* Map the device if it has the same details as before. */
613 if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
614 weston_log("Mapping frame buffer failed.\n");
624 /* NOTE: This leaves output->fb_info populated, caching data so that if
625 * fbdev_output_reenable() is called again, it can determine whether a mode-set
628 fbdev_output_disable(struct weston_output *base)
630 struct fbdev_output *output = to_fbdev_output(base);
632 weston_log("Disabling fbdev output.\n");
634 if (output->hw_surface != NULL) {
635 pixman_image_unref(output->hw_surface);
636 output->hw_surface = NULL;
639 fbdev_frame_buffer_destroy(output);
643 fbdev_backend_destroy(struct weston_compositor *base)
645 struct fbdev_backend *backend = to_fbdev_backend(base);
647 udev_input_destroy(&backend->input);
649 /* Destroy the output. */
650 weston_compositor_shutdown(base);
653 weston_launcher_destroy(base->launcher);
659 session_notify(struct wl_listener *listener, void *data)
661 struct weston_compositor *compositor = data;
662 struct fbdev_backend *backend = to_fbdev_backend(compositor);
663 struct weston_output *output;
665 if (compositor->session_active) {
666 weston_log("entering VT\n");
667 compositor->state = backend->prev_state;
669 wl_list_for_each(output, &compositor->output_list, link) {
670 fbdev_output_reenable(backend, output);
673 weston_compositor_damage_all(compositor);
675 udev_input_enable(&backend->input);
677 weston_log("leaving VT\n");
678 udev_input_disable(&backend->input);
680 wl_list_for_each(output, &compositor->output_list, link) {
681 fbdev_output_disable(output);
684 backend->prev_state = compositor->state;
685 weston_compositor_offscreen(compositor);
687 /* If we have a repaint scheduled (from the idle handler), make
688 * sure we cancel that so we don't try to pageflip when we're
689 * vt switched away. The OFFSCREEN state will prevent
690 * further attempts at repainting. When we switch
691 * back, we schedule a repaint, which will process
692 * pending frame callbacks. */
694 wl_list_for_each(output,
695 &compositor->output_list, link) {
696 output->repaint_needed = 0;
702 fbdev_restore(struct weston_compositor *compositor)
704 weston_launcher_restore(compositor->launcher);
707 static struct fbdev_backend *
708 fbdev_backend_create(struct weston_compositor *compositor,
709 struct weston_fbdev_backend_config *param)
711 struct fbdev_backend *backend;
712 const char *seat_id = default_seat;
714 weston_log("initializing fbdev backend\n");
716 backend = zalloc(sizeof *backend);
720 backend->compositor = compositor;
721 if (weston_compositor_set_presentation_clock_software(
725 backend->udev = udev_new();
726 if (backend->udev == NULL) {
727 weston_log("Failed to initialize udev context.\n");
731 /* Set up the TTY. */
732 backend->session_listener.notify = session_notify;
733 wl_signal_add(&compositor->session_signal,
734 &backend->session_listener);
735 compositor->launcher =
736 weston_launcher_connect(compositor, param->tty, "seat0", false);
737 if (!compositor->launcher) {
738 weston_log("fatal: fbdev backend should be run "
739 "using weston-launch binary or as root\n");
743 backend->base.destroy = fbdev_backend_destroy;
744 backend->base.restore = fbdev_restore;
746 backend->prev_state = WESTON_COMPOSITOR_ACTIVE;
748 weston_setup_vt_switch_bindings(compositor);
750 if (pixman_renderer_init(compositor) < 0)
753 if (fbdev_output_create(backend, param->device) < 0)
756 udev_input_init(&backend->input, compositor, backend->udev,
757 seat_id, param->configure_device);
759 compositor->backend = &backend->base;
763 weston_launcher_destroy(compositor->launcher);
766 udev_unref(backend->udev);
769 weston_compositor_shutdown(compositor);
776 config_init_to_defaults(struct weston_fbdev_backend_config *config)
778 /* TODO: Ideally, available frame buffers should be enumerated using
779 * udev, rather than passing a device node in as a parameter. */
780 config->tty = 0; /* default to current tty */
781 config->device = "/dev/fb0"; /* default frame buffer */
785 weston_backend_init(struct weston_compositor *compositor,
786 struct weston_backend_config *config_base)
788 struct fbdev_backend *b;
789 struct weston_fbdev_backend_config config = {{ 0, }};
791 if (config_base == NULL ||
792 config_base->struct_version != WESTON_FBDEV_BACKEND_CONFIG_VERSION ||
793 config_base->struct_size > sizeof(struct weston_fbdev_backend_config)) {
794 weston_log("fbdev backend config structure is invalid\n");
798 config_init_to_defaults(&config);
799 memcpy(&config, config_base, config_base->struct_size);
801 b = fbdev_backend_create(compositor, &config);