blob: 7465df6d087d3e8800d62403c87201629c0dc77d [file] [log] [blame]
Philip Withnall4f499172013-02-02 12:02:32 +00001/*
2 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
4 * Copyright © 2012 Raspberry Pi Foundation
5 * Copyright © 2013 Philip Withnall
6 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07007 * 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:
Philip Withnall4f499172013-02-02 12:02:32 +000014 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070015 * 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.
18 *
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
26 * SOFTWARE.
Philip Withnall4f499172013-02-02 12:02:32 +000027 */
28
Daniel Stonec228e232013-05-22 18:03:19 +030029#include "config.h"
Philip Withnall4f499172013-02-02 12:02:32 +000030
31#include <errno.h>
32#include <stdlib.h>
33#include <stdio.h>
34#include <string.h>
35#include <math.h>
36#include <sys/mman.h>
37#include <sys/types.h>
38#include <fcntl.h>
39#include <unistd.h>
40#include <linux/fb.h>
Kristian Høgsberg7e597f22013-02-18 16:35:26 -050041#include <linux/input.h>
Philip Withnall4f499172013-02-02 12:02:32 +000042
43#include <libudev.h>
44
Jon Cruz35b2eaa2015-06-15 15:37:08 -070045#include "shared/helpers.h"
Philip Withnall4f499172013-02-02 12:02:32 +000046#include "compositor.h"
47#include "launcher-util.h"
48#include "pixman-renderer.h"
Peter Hutterer823ad332014-11-26 07:06:31 +100049#include "libinput-seat.h"
Adrian Negreanu4aa756d2013-09-06 15:16:09 +030050#include "gl-renderer.h"
Pekka Paalanen363aa7b2014-12-17 16:20:40 +020051#include "presentation_timing-server-protocol.h"
Philip Withnall4f499172013-02-02 12:02:32 +000052
Giulio Camuffo954f1832014-10-11 18:27:30 +030053struct fbdev_backend {
54 struct weston_backend base;
55 struct weston_compositor *compositor;
Philip Withnall4f499172013-02-02 12:02:32 +000056 uint32_t prev_state;
57
58 struct udev *udev;
Rob Bradfordd355b802013-05-31 18:09:55 +010059 struct udev_input input;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +030060 int use_pixman;
Kristian Høgsberg61741a22013-09-17 16:02:57 -070061 struct wl_listener session_listener;
Philip Withnall4f499172013-02-02 12:02:32 +000062};
63
64struct fbdev_screeninfo {
65 unsigned int x_resolution; /* pixels, visible area */
66 unsigned int y_resolution; /* pixels, visible area */
67 unsigned int width_mm; /* visible screen width in mm */
68 unsigned int height_mm; /* visible screen height in mm */
69 unsigned int bits_per_pixel;
70
71 size_t buffer_length; /* length of frame buffer memory in bytes */
72 size_t line_length; /* length of a line in bytes */
73 char id[16]; /* screen identifier */
74
75 pixman_format_code_t pixel_format; /* frame buffer pixel format */
76 unsigned int refresh_rate; /* Hertz */
77};
78
79struct fbdev_output {
Giulio Camuffo954f1832014-10-11 18:27:30 +030080 struct fbdev_backend *backend;
Philip Withnall4f499172013-02-02 12:02:32 +000081 struct weston_output base;
82
83 struct weston_mode mode;
84 struct wl_event_source *finish_frame_timer;
85
86 /* Frame buffer details. */
87 const char *device; /* ownership shared with fbdev_parameters */
88 struct fbdev_screeninfo fb_info;
89 void *fb; /* length is fb_info.buffer_length */
90
91 /* pixman details. */
92 pixman_image_t *hw_surface;
93 pixman_image_t *shadow_surface;
94 void *shadow_buf;
95 uint8_t depth;
96};
97
Philip Withnall4f499172013-02-02 12:02:32 +000098struct fbdev_parameters {
99 int tty;
100 char *device;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300101 int use_gl;
Philip Withnall4f499172013-02-02 12:02:32 +0000102};
103
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300104struct gl_renderer_interface *gl_renderer;
105
Kristian Høgsberg7e597f22013-02-18 16:35:26 -0500106static const char default_seat[] = "seat0";
107
Philip Withnall4f499172013-02-02 12:02:32 +0000108static inline struct fbdev_output *
109to_fbdev_output(struct weston_output *base)
110{
111 return container_of(base, struct fbdev_output, base);
112}
113
Giulio Camuffo954f1832014-10-11 18:27:30 +0300114static inline struct fbdev_backend *
115to_fbdev_backend(struct weston_compositor *base)
Philip Withnall4f499172013-02-02 12:02:32 +0000116{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300117 return container_of(base->backend, struct fbdev_backend, base);
Philip Withnall4f499172013-02-02 12:02:32 +0000118}
119
120static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200121fbdev_output_start_repaint_loop(struct weston_output *output)
122{
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400123 struct timespec ts;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200124
Pekka Paalanen662f3842015-03-18 12:17:26 +0200125 weston_compositor_read_presentation_clock(output->compositor, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200126 weston_output_finish_frame(output, &ts, PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200127}
128
129static void
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300130fbdev_output_repaint_pixman(struct weston_output *base, pixman_region32_t *damage)
Philip Withnall4f499172013-02-02 12:02:32 +0000131{
132 struct fbdev_output *output = to_fbdev_output(base);
133 struct weston_compositor *ec = output->base.compositor;
134 pixman_box32_t *rects;
Derek Foreman561662b2015-03-17 13:22:38 -0500135 int nrects, i;
Philip Withnall4f499172013-02-02 12:02:32 +0000136
137 /* Repaint the damaged region onto the back buffer. */
138 pixman_renderer_output_set_buffer(base, output->shadow_surface);
139 ec->renderer->repaint_output(base, damage);
140
141 /* Transform and composite onto the frame buffer. */
Philip Withnall4f499172013-02-02 12:02:32 +0000142 rects = pixman_region32_rectangles(damage, &nrects);
143
144 for (i = 0; i < nrects; i++) {
Derek Foreman561662b2015-03-17 13:22:38 -0500145 pixman_box32_t transformed_rect;
146 int width, height;
Philip Withnall4f499172013-02-02 12:02:32 +0000147
Derek Foreman561662b2015-03-17 13:22:38 -0500148 transformed_rect = weston_transformed_rect(base->width,
149 base->height,
150 base->transform,
151 1, rects[i]);
152 width = transformed_rect.x2 - transformed_rect.x1;
153 height = transformed_rect.y2 - transformed_rect.y1;
Philip Withnall4f499172013-02-02 12:02:32 +0000154 pixman_image_composite32(PIXMAN_OP_SRC,
155 output->shadow_surface, /* src */
156 NULL /* mask */,
157 output->hw_surface, /* dest */
Derek Foreman561662b2015-03-17 13:22:38 -0500158 transformed_rect.x1, /* src_x */
159 transformed_rect.y1, /* src_y */
Philip Withnall4f499172013-02-02 12:02:32 +0000160 0, 0, /* mask_x, mask_y */
Derek Foreman561662b2015-03-17 13:22:38 -0500161 transformed_rect.x1, /* dest_x */
162 transformed_rect.y1, /* dest_y */
163 width, /* width */
164 height /* height */);
Philip Withnall4f499172013-02-02 12:02:32 +0000165 }
166
167 /* Update the damage region. */
168 pixman_region32_subtract(&ec->primary_plane.damage,
169 &ec->primary_plane.damage, damage);
170
171 /* Schedule the end of the frame. We do not sync this to the frame
172 * buffer clock because users who want that should be using the DRM
173 * compositor. FBIO_WAITFORVSYNC blocks and FB_ACTIVATE_VBL requires
174 * panning, which is broken in most kernel drivers.
175 *
176 * Finish the frame synchronised to the specified refresh rate. The
177 * refresh rate is given in mHz and the interval in ms. */
178 wl_event_source_timer_update(output->finish_frame_timer,
179 1000000 / output->mode.refresh);
180}
181
David Herrmann1edf44c2013-10-22 17:11:26 +0200182static int
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300183fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage)
184{
185 struct fbdev_output *output = to_fbdev_output(base);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300186 struct fbdev_backend *fbb = output->backend;
187 struct weston_compositor *ec = fbb->compositor;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300188
Giulio Camuffo954f1832014-10-11 18:27:30 +0300189 if (fbb->use_pixman) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300190 fbdev_output_repaint_pixman(base,damage);
191 } else {
192 ec->renderer->repaint_output(base, damage);
193 /* Update the damage region. */
194 pixman_region32_subtract(&ec->primary_plane.damage,
195 &ec->primary_plane.damage, damage);
196
197 wl_event_source_timer_update(output->finish_frame_timer,
198 1000000 / output->mode.refresh);
199 }
David Herrmann1edf44c2013-10-22 17:11:26 +0200200
201 return 0;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300202}
203
Philip Withnall4f499172013-02-02 12:02:32 +0000204static int
205finish_frame_handler(void *data)
206{
207 struct fbdev_output *output = data;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200208 struct timespec ts;
Philip Withnall4f499172013-02-02 12:02:32 +0000209
Pekka Paalanen662f3842015-03-18 12:17:26 +0200210 weston_compositor_read_presentation_clock(output->base.compositor, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200211 weston_output_finish_frame(&output->base, &ts, 0);
Philip Withnall4f499172013-02-02 12:02:32 +0000212
213 return 1;
214}
215
216static pixman_format_code_t
217calculate_pixman_format(struct fb_var_screeninfo *vinfo,
218 struct fb_fix_screeninfo *finfo)
219{
220 /* Calculate the pixman format supported by the frame buffer from the
221 * buffer's metadata. Return 0 if no known pixman format is supported
222 * (since this has depth 0 it's guaranteed to not conflict with any
223 * actual pixman format).
224 *
225 * Documentation on the vinfo and finfo structures:
226 * http://www.mjmwired.net/kernel/Documentation/fb/api.txt
227 *
228 * TODO: Try a bit harder to support other formats, including setting
229 * the preferred format in the hardware. */
230 int type;
231
232 weston_log("Calculating pixman format from:\n"
233 STAMP_SPACE " - type: %i (aux: %i)\n"
234 STAMP_SPACE " - visual: %i\n"
235 STAMP_SPACE " - bpp: %i (grayscale: %i)\n"
236 STAMP_SPACE " - red: offset: %i, length: %i, MSB: %i\n"
237 STAMP_SPACE " - green: offset: %i, length: %i, MSB: %i\n"
238 STAMP_SPACE " - blue: offset: %i, length: %i, MSB: %i\n"
239 STAMP_SPACE " - transp: offset: %i, length: %i, MSB: %i\n",
240 finfo->type, finfo->type_aux, finfo->visual,
241 vinfo->bits_per_pixel, vinfo->grayscale,
242 vinfo->red.offset, vinfo->red.length, vinfo->red.msb_right,
243 vinfo->green.offset, vinfo->green.length,
244 vinfo->green.msb_right,
245 vinfo->blue.offset, vinfo->blue.length,
246 vinfo->blue.msb_right,
247 vinfo->transp.offset, vinfo->transp.length,
248 vinfo->transp.msb_right);
249
250 /* We only handle packed formats at the moment. */
251 if (finfo->type != FB_TYPE_PACKED_PIXELS)
252 return 0;
253
254 /* We only handle true-colour frame buffers at the moment. */
Marc Chalainffbddff2013-09-03 16:47:43 +0200255 switch(finfo->visual) {
256 case FB_VISUAL_TRUECOLOR:
257 case FB_VISUAL_DIRECTCOLOR:
258 if (vinfo->grayscale != 0)
259 return 0;
260 break;
261 default:
262 return 0;
263 }
Philip Withnall4f499172013-02-02 12:02:32 +0000264
265 /* We only support formats with MSBs on the left. */
266 if (vinfo->red.msb_right != 0 || vinfo->green.msb_right != 0 ||
267 vinfo->blue.msb_right != 0)
268 return 0;
269
270 /* Work out the format type from the offsets. We only support RGBA and
271 * ARGB at the moment. */
272 type = PIXMAN_TYPE_OTHER;
273
274 if ((vinfo->transp.offset >= vinfo->red.offset ||
275 vinfo->transp.length == 0) &&
276 vinfo->red.offset >= vinfo->green.offset &&
277 vinfo->green.offset >= vinfo->blue.offset)
278 type = PIXMAN_TYPE_ARGB;
279 else if (vinfo->red.offset >= vinfo->green.offset &&
280 vinfo->green.offset >= vinfo->blue.offset &&
281 vinfo->blue.offset >= vinfo->transp.offset)
282 type = PIXMAN_TYPE_RGBA;
283
284 if (type == PIXMAN_TYPE_OTHER)
285 return 0;
286
287 /* Build the format. */
288 return PIXMAN_FORMAT(vinfo->bits_per_pixel, type,
289 vinfo->transp.length,
290 vinfo->red.length,
291 vinfo->green.length,
292 vinfo->blue.length);
293}
294
295static int
296calculate_refresh_rate(struct fb_var_screeninfo *vinfo)
297{
298 uint64_t quot;
299
300 /* Calculate monitor refresh rate. Default is 60 Hz. Units are mHz. */
301 quot = (vinfo->upper_margin + vinfo->lower_margin + vinfo->yres);
302 quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres);
303 quot *= vinfo->pixclock;
304
305 if (quot > 0) {
306 uint64_t refresh_rate;
307
308 refresh_rate = 1000000000000000LLU / quot;
309 if (refresh_rate > 200000)
310 refresh_rate = 200000; /* cap at 200 Hz */
311
312 return refresh_rate;
313 }
314
315 return 60 * 1000; /* default to 60 Hz */
316}
317
318static int
319fbdev_query_screen_info(struct fbdev_output *output, int fd,
320 struct fbdev_screeninfo *info)
321{
322 struct fb_var_screeninfo varinfo;
323 struct fb_fix_screeninfo fixinfo;
324
325 /* Probe the device for screen information. */
326 if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) < 0 ||
327 ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
328 return -1;
329 }
330
331 /* Store the pertinent data. */
332 info->x_resolution = varinfo.xres;
333 info->y_resolution = varinfo.yres;
334 info->width_mm = varinfo.width;
335 info->height_mm = varinfo.height;
336 info->bits_per_pixel = varinfo.bits_per_pixel;
337
338 info->buffer_length = fixinfo.smem_len;
339 info->line_length = fixinfo.line_length;
Derek Foreman61793382015-09-02 13:45:20 -0500340 strncpy(info->id, fixinfo.id, sizeof(info->id));
Bryce Harrington44bbdd02015-09-23 17:39:05 -0700341 info->id[sizeof(info->id)-1] = '\0';
Philip Withnall4f499172013-02-02 12:02:32 +0000342
343 info->pixel_format = calculate_pixman_format(&varinfo, &fixinfo);
344 info->refresh_rate = calculate_refresh_rate(&varinfo);
345
346 if (info->pixel_format == 0) {
347 weston_log("Frame buffer uses an unsupported format.\n");
348 return -1;
349 }
350
351 return 1;
352}
353
354static int
355fbdev_set_screen_info(struct fbdev_output *output, int fd,
356 struct fbdev_screeninfo *info)
357{
358 struct fb_var_screeninfo varinfo;
359
360 /* Grab the current screen information. */
361 if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
362 return -1;
363 }
364
365 /* Update the information. */
366 varinfo.xres = info->x_resolution;
367 varinfo.yres = info->y_resolution;
368 varinfo.width = info->width_mm;
369 varinfo.height = info->height_mm;
370 varinfo.bits_per_pixel = info->bits_per_pixel;
371
372 /* Try to set up an ARGB (x8r8g8b8) pixel format. */
373 varinfo.grayscale = 0;
374 varinfo.transp.offset = 24;
375 varinfo.transp.length = 0;
376 varinfo.transp.msb_right = 0;
377 varinfo.red.offset = 16;
378 varinfo.red.length = 8;
379 varinfo.red.msb_right = 0;
380 varinfo.green.offset = 8;
381 varinfo.green.length = 8;
382 varinfo.green.msb_right = 0;
383 varinfo.blue.offset = 0;
384 varinfo.blue.length = 8;
385 varinfo.blue.msb_right = 0;
386
387 /* Set the device's screen information. */
388 if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
389 return -1;
390 }
391
392 return 1;
393}
394
395static void fbdev_frame_buffer_destroy(struct fbdev_output *output);
396
397/* Returns an FD for the frame buffer device. */
398static int
399fbdev_frame_buffer_open(struct fbdev_output *output, const char *fb_dev,
400 struct fbdev_screeninfo *screen_info)
401{
402 int fd = -1;
403
404 weston_log("Opening fbdev frame buffer.\n");
405
406 /* Open the frame buffer device. */
407 fd = open(fb_dev, O_RDWR | O_CLOEXEC);
408 if (fd < 0) {
409 weston_log("Failed to open frame buffer device ‘%s’: %s\n",
410 fb_dev, strerror(errno));
411 return -1;
412 }
413
414 /* Grab the screen info. */
415 if (fbdev_query_screen_info(output, fd, screen_info) < 0) {
416 weston_log("Failed to get frame buffer info: %s\n",
417 strerror(errno));
418
419 close(fd);
420 return -1;
421 }
422
423 return fd;
424}
425
426/* Closes the FD on success or failure. */
427static int
428fbdev_frame_buffer_map(struct fbdev_output *output, int fd)
429{
430 int retval = -1;
431
432 weston_log("Mapping fbdev frame buffer.\n");
433
434 /* Map the frame buffer. Write-only mode, since we don't want to read
435 * anything back (because it's slow). */
436 output->fb = mmap(NULL, output->fb_info.buffer_length,
437 PROT_WRITE, MAP_SHARED, fd, 0);
438 if (output->fb == MAP_FAILED) {
439 weston_log("Failed to mmap frame buffer: %s\n",
440 strerror(errno));
441 goto out_close;
442 }
443
444 /* Create a pixman image to wrap the memory mapped frame buffer. */
445 output->hw_surface =
446 pixman_image_create_bits(output->fb_info.pixel_format,
447 output->fb_info.x_resolution,
448 output->fb_info.y_resolution,
449 output->fb,
450 output->fb_info.line_length);
451 if (output->hw_surface == NULL) {
452 weston_log("Failed to create surface for frame buffer.\n");
453 goto out_unmap;
454 }
455
456 /* Success! */
457 retval = 0;
458
459out_unmap:
460 if (retval != 0 && output->fb != NULL)
461 fbdev_frame_buffer_destroy(output);
462
463out_close:
464 if (fd >= 0)
465 close(fd);
466
467 return retval;
468}
469
470static void
471fbdev_frame_buffer_destroy(struct fbdev_output *output)
472{
473 weston_log("Destroying fbdev frame buffer.\n");
474
475 if (munmap(output->fb, output->fb_info.buffer_length) < 0)
476 weston_log("Failed to munmap frame buffer: %s\n",
477 strerror(errno));
478
479 output->fb = NULL;
480}
481
482static void fbdev_output_destroy(struct weston_output *base);
483static void fbdev_output_disable(struct weston_output *base);
484
485static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300486fbdev_output_create(struct fbdev_backend *backend,
Philip Withnall4f499172013-02-02 12:02:32 +0000487 const char *device)
488{
489 struct fbdev_output *output;
Derek Foreman44ed70b2015-03-17 13:22:37 -0500490 struct weston_config_section *section;
Philip Withnall4f499172013-02-02 12:02:32 +0000491 int fb_fd;
Philip Withnall4f499172013-02-02 12:02:32 +0000492 int width, height;
493 unsigned int bytes_per_pixel;
494 struct wl_event_loop *loop;
Derek Foreman44ed70b2015-03-17 13:22:37 -0500495 uint32_t config_transform;
496 char *s;
Philip Withnall4f499172013-02-02 12:02:32 +0000497
498 weston_log("Creating fbdev output.\n");
499
Bryce Harringtonde16d892014-11-20 22:21:57 -0800500 output = zalloc(sizeof *output);
501 if (output == NULL)
Philip Withnall4f499172013-02-02 12:02:32 +0000502 return -1;
503
Giulio Camuffo954f1832014-10-11 18:27:30 +0300504 output->backend = backend;
Philip Withnall4f499172013-02-02 12:02:32 +0000505 output->device = device;
506
507 /* Create the frame buffer. */
508 fb_fd = fbdev_frame_buffer_open(output, device, &output->fb_info);
509 if (fb_fd < 0) {
510 weston_log("Creating frame buffer failed.\n");
511 goto out_free;
512 }
Giulio Camuffo954f1832014-10-11 18:27:30 +0300513 if (backend->use_pixman) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300514 if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
515 weston_log("Mapping frame buffer failed.\n");
516 goto out_free;
517 }
Kristian Høgsberg8ac6a2d2013-10-09 09:59:06 -0700518 } else {
519 close(fb_fd);
Philip Withnall4f499172013-02-02 12:02:32 +0000520 }
521
Jonas Ådahle5a12252013-04-05 23:07:11 +0200522 output->base.start_repaint_loop = fbdev_output_start_repaint_loop;
Philip Withnall4f499172013-02-02 12:02:32 +0000523 output->base.repaint = fbdev_output_repaint;
524 output->base.destroy = fbdev_output_destroy;
Philip Withnall4f499172013-02-02 12:02:32 +0000525
526 /* only one static mode in list */
527 output->mode.flags =
528 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
529 output->mode.width = output->fb_info.x_resolution;
530 output->mode.height = output->fb_info.y_resolution;
531 output->mode.refresh = output->fb_info.refresh_rate;
532 wl_list_init(&output->base.mode_list);
533 wl_list_insert(&output->base.mode_list, &output->mode.link);
534
Hardeningff39efa2013-09-18 23:56:35 +0200535 output->base.current_mode = &output->mode;
Philip Withnall4f499172013-02-02 12:02:32 +0000536 output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
537 output->base.make = "unknown";
538 output->base.model = output->fb_info.id;
Derek Foremane516c3b2015-03-17 13:22:34 -0500539 output->base.name = strdup("fbdev");
Philip Withnall4f499172013-02-02 12:02:32 +0000540
Giulio Camuffo954f1832014-10-11 18:27:30 +0300541 section = weston_config_get_section(backend->compositor->config,
Derek Foreman44ed70b2015-03-17 13:22:37 -0500542 "output", "name",
543 output->base.name);
544 weston_config_section_get_string(section, "transform", &s, "normal");
545 if (weston_parse_transform(s, &config_transform) < 0)
546 weston_log("Invalid transform \"%s\" for output %s\n",
547 s, output->base.name);
548 free(s);
549
Giulio Camuffo954f1832014-10-11 18:27:30 +0300550 weston_output_init(&output->base, backend->compositor,
Philip Withnall4f499172013-02-02 12:02:32 +0000551 0, 0, output->fb_info.width_mm,
552 output->fb_info.height_mm,
Derek Foreman44ed70b2015-03-17 13:22:37 -0500553 config_transform,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200554 1);
Philip Withnall4f499172013-02-02 12:02:32 +0000555
Derek Foreman561662b2015-03-17 13:22:38 -0500556 width = output->mode.width;
557 height = output->mode.height;
Philip Withnall4f499172013-02-02 12:02:32 +0000558 bytes_per_pixel = output->fb_info.bits_per_pixel / 8;
559
560 output->shadow_buf = malloc(width * height * bytes_per_pixel);
561 output->shadow_surface =
562 pixman_image_create_bits(output->fb_info.pixel_format,
Derek Foreman561662b2015-03-17 13:22:38 -0500563 width, height,
Philip Withnall4f499172013-02-02 12:02:32 +0000564 output->shadow_buf,
Derek Foreman561662b2015-03-17 13:22:38 -0500565 width * bytes_per_pixel);
Philip Withnall4f499172013-02-02 12:02:32 +0000566 if (output->shadow_buf == NULL || output->shadow_surface == NULL) {
567 weston_log("Failed to create surface for frame buffer.\n");
568 goto out_hw_surface;
569 }
570
Giulio Camuffo954f1832014-10-11 18:27:30 +0300571 if (backend->use_pixman) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300572 if (pixman_renderer_output_create(&output->base) < 0)
573 goto out_shadow_surface;
574 } else {
575 setenv("HYBRIS_EGLPLATFORM", "wayland", 1);
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300576 if (gl_renderer->output_create(&output->base,
Jonny Lamb671148f2015-03-20 15:26:52 +0100577 (EGLNativeWindowType)NULL, NULL,
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000578 gl_renderer->opaque_attribs,
Derek Foremane76f1852015-05-15 12:12:39 -0500579 NULL, 0) < 0) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300580 weston_log("gl_renderer_output_create failed.\n");
581 goto out_shadow_surface;
582 }
583 }
584
Philip Withnall4f499172013-02-02 12:02:32 +0000585
Giulio Camuffo954f1832014-10-11 18:27:30 +0300586 loop = wl_display_get_event_loop(backend->compositor->wl_display);
Philip Withnall4f499172013-02-02 12:02:32 +0000587 output->finish_frame_timer =
588 wl_event_loop_add_timer(loop, finish_frame_handler, output);
589
Giulio Camuffo954f1832014-10-11 18:27:30 +0300590 weston_compositor_add_output(backend->compositor, &output->base);
Philip Withnall4f499172013-02-02 12:02:32 +0000591
592 weston_log("fbdev output %d×%d px\n",
593 output->mode.width, output->mode.height);
594 weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
595 output->mode.refresh / 1000);
596
597 return 0;
598
599out_shadow_surface:
600 pixman_image_unref(output->shadow_surface);
601 output->shadow_surface = NULL;
602out_hw_surface:
603 free(output->shadow_buf);
604 pixman_image_unref(output->hw_surface);
605 output->hw_surface = NULL;
606 weston_output_destroy(&output->base);
607 fbdev_frame_buffer_destroy(output);
608out_free:
609 free(output);
610
611 return -1;
612}
613
614static void
615fbdev_output_destroy(struct weston_output *base)
616{
617 struct fbdev_output *output = to_fbdev_output(base);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300618 struct fbdev_backend *backend = output->backend;
Philip Withnall4f499172013-02-02 12:02:32 +0000619
620 weston_log("Destroying fbdev output.\n");
621
622 /* Close the frame buffer. */
623 fbdev_output_disable(base);
624
Giulio Camuffo954f1832014-10-11 18:27:30 +0300625 if (backend->use_pixman) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300626 if (base->renderer_state != NULL)
627 pixman_renderer_output_destroy(base);
Philip Withnall4f499172013-02-02 12:02:32 +0000628
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300629 if (output->shadow_surface != NULL) {
630 pixman_image_unref(output->shadow_surface);
631 output->shadow_surface = NULL;
632 }
Philip Withnall4f499172013-02-02 12:02:32 +0000633
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300634 if (output->shadow_buf != NULL) {
635 free(output->shadow_buf);
636 output->shadow_buf = NULL;
637 }
638 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300639 gl_renderer->output_destroy(base);
Philip Withnall4f499172013-02-02 12:02:32 +0000640 }
641
642 /* Remove the output. */
Philip Withnall4f499172013-02-02 12:02:32 +0000643 weston_output_destroy(&output->base);
644
645 free(output);
646}
647
648/* strcmp()-style return values. */
649static int
650compare_screen_info (const struct fbdev_screeninfo *a,
651 const struct fbdev_screeninfo *b)
652{
653 if (a->x_resolution == b->x_resolution &&
654 a->y_resolution == b->y_resolution &&
655 a->width_mm == b->width_mm &&
656 a->height_mm == b->height_mm &&
657 a->bits_per_pixel == b->bits_per_pixel &&
658 a->pixel_format == b->pixel_format &&
659 a->refresh_rate == b->refresh_rate)
660 return 0;
661
662 return 1;
663}
664
665static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300666fbdev_output_reenable(struct fbdev_backend *backend,
Philip Withnall4f499172013-02-02 12:02:32 +0000667 struct weston_output *base)
668{
669 struct fbdev_output *output = to_fbdev_output(base);
670 struct fbdev_screeninfo new_screen_info;
671 int fb_fd;
Rob Bradfordf8ef42f2013-07-26 16:29:38 +0100672 const char *device;
Philip Withnall4f499172013-02-02 12:02:32 +0000673
674 weston_log("Re-enabling fbdev output.\n");
675
676 /* Create the frame buffer. */
677 fb_fd = fbdev_frame_buffer_open(output, output->device,
678 &new_screen_info);
679 if (fb_fd < 0) {
680 weston_log("Creating frame buffer failed.\n");
681 goto err;
682 }
683
684 /* Check whether the frame buffer details have changed since we were
685 * disabled. */
686 if (compare_screen_info (&output->fb_info, &new_screen_info) != 0) {
687 /* Perform a mode-set to restore the old mode. */
688 if (fbdev_set_screen_info(output, fb_fd,
689 &output->fb_info) < 0) {
690 weston_log("Failed to restore mode settings. "
691 "Attempting to re-open output anyway.\n");
692 }
693
Rob Bradford581b3fd2013-07-26 16:29:39 +0100694 close(fb_fd);
695
Philip Withnall4f499172013-02-02 12:02:32 +0000696 /* Remove and re-add the output so that resources depending on
697 * the frame buffer X/Y resolution (such as the shadow buffer)
698 * are re-initialised. */
Rob Bradfordf8ef42f2013-07-26 16:29:38 +0100699 device = output->device;
Philip Withnall4f499172013-02-02 12:02:32 +0000700 fbdev_output_destroy(base);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300701 fbdev_output_create(backend, device);
Philip Withnall4f499172013-02-02 12:02:32 +0000702
703 return 0;
704 }
705
706 /* Map the device if it has the same details as before. */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300707 if (backend->use_pixman) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300708 if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
709 weston_log("Mapping frame buffer failed.\n");
710 goto err;
711 }
Philip Withnall4f499172013-02-02 12:02:32 +0000712 }
713
714 return 0;
715
716err:
717 return -1;
718}
719
720/* NOTE: This leaves output->fb_info populated, caching data so that if
721 * fbdev_output_reenable() is called again, it can determine whether a mode-set
722 * is needed. */
723static void
724fbdev_output_disable(struct weston_output *base)
725{
726 struct fbdev_output *output = to_fbdev_output(base);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300727 struct fbdev_backend *backend = output->backend;
Philip Withnall4f499172013-02-02 12:02:32 +0000728
729 weston_log("Disabling fbdev output.\n");
730
Giulio Camuffo954f1832014-10-11 18:27:30 +0300731 if ( ! backend->use_pixman) return;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300732
Philip Withnall4f499172013-02-02 12:02:32 +0000733 if (output->hw_surface != NULL) {
734 pixman_image_unref(output->hw_surface);
735 output->hw_surface = NULL;
736 }
737
738 fbdev_frame_buffer_destroy(output);
739}
740
741static void
Giulio Camuffo954f1832014-10-11 18:27:30 +0300742fbdev_backend_destroy(struct weston_compositor *base)
Philip Withnall4f499172013-02-02 12:02:32 +0000743{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300744 struct fbdev_backend *backend = to_fbdev_backend(base);
Philip Withnall4f499172013-02-02 12:02:32 +0000745
Giulio Camuffo954f1832014-10-11 18:27:30 +0300746 udev_input_destroy(&backend->input);
Philip Withnall4f499172013-02-02 12:02:32 +0000747
748 /* Destroy the output. */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300749 weston_compositor_shutdown(base);
Philip Withnall4f499172013-02-02 12:02:32 +0000750
751 /* Chain up. */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300752 weston_launcher_destroy(base->launcher);
Philip Withnall4f499172013-02-02 12:02:32 +0000753
Giulio Camuffo954f1832014-10-11 18:27:30 +0300754 free(backend);
Philip Withnall4f499172013-02-02 12:02:32 +0000755}
756
757static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700758session_notify(struct wl_listener *listener, void *data)
Philip Withnall4f499172013-02-02 12:02:32 +0000759{
Pekka Paalanen3f897942015-08-19 13:52:47 +0300760 struct weston_compositor *compositor = data;
761 struct fbdev_backend *backend = to_fbdev_backend(compositor);
Philip Withnall4f499172013-02-02 12:02:32 +0000762 struct weston_output *output;
763
Giulio Camuffo954f1832014-10-11 18:27:30 +0300764 if (compositor->session_active) {
Philip Withnall4f499172013-02-02 12:02:32 +0000765 weston_log("entering VT\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +0300766 compositor->state = backend->prev_state;
Philip Withnall4f499172013-02-02 12:02:32 +0000767
Giulio Camuffo954f1832014-10-11 18:27:30 +0300768 wl_list_for_each(output, &compositor->output_list, link) {
769 fbdev_output_reenable(backend, output);
Philip Withnall4f499172013-02-02 12:02:32 +0000770 }
771
Giulio Camuffo954f1832014-10-11 18:27:30 +0300772 weston_compositor_damage_all(compositor);
Philip Withnall4f499172013-02-02 12:02:32 +0000773
Giulio Camuffo954f1832014-10-11 18:27:30 +0300774 udev_input_enable(&backend->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700775 } else {
Philip Withnall4f499172013-02-02 12:02:32 +0000776 weston_log("leaving VT\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +0300777 udev_input_disable(&backend->input);
Philip Withnall4f499172013-02-02 12:02:32 +0000778
Giulio Camuffo954f1832014-10-11 18:27:30 +0300779 wl_list_for_each(output, &compositor->output_list, link) {
Philip Withnall4f499172013-02-02 12:02:32 +0000780 fbdev_output_disable(output);
781 }
782
Giulio Camuffo954f1832014-10-11 18:27:30 +0300783 backend->prev_state = compositor->state;
784 weston_compositor_offscreen(compositor);
Philip Withnall4f499172013-02-02 12:02:32 +0000785
786 /* If we have a repaint scheduled (from the idle handler), make
787 * sure we cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +0100788 * vt switched away. The OFFSCREEN state will prevent
Philip Withnall4f499172013-02-02 12:02:32 +0000789 * further attemps at repainting. When we switch
790 * back, we schedule a repaint, which will process
791 * pending frame callbacks. */
792
793 wl_list_for_each(output,
Giulio Camuffo954f1832014-10-11 18:27:30 +0300794 &compositor->output_list, link) {
Philip Withnall4f499172013-02-02 12:02:32 +0000795 output->repaint_needed = 0;
796 }
nerdopolis38946702014-12-03 15:53:03 +0000797 }
Philip Withnall4f499172013-02-02 12:02:32 +0000798}
799
800static void
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700801fbdev_restore(struct weston_compositor *compositor)
Philip Withnall4f499172013-02-02 12:02:32 +0000802{
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700803 weston_launcher_restore(compositor->launcher);
Philip Withnall4f499172013-02-02 12:02:32 +0000804}
805
806static void
Derek Foreman8ae2db52015-07-15 13:00:36 -0500807switch_vt_binding(struct weston_keyboard *keyboard, uint32_t time,
808 uint32_t key, void *data)
Philip Withnall4f499172013-02-02 12:02:32 +0000809{
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700810 struct weston_compositor *compositor = data;
Philip Withnall4f499172013-02-02 12:02:32 +0000811
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700812 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Philip Withnall4f499172013-02-02 12:02:32 +0000813}
814
Giulio Camuffo954f1832014-10-11 18:27:30 +0300815static struct fbdev_backend *
816fbdev_backend_create(struct weston_compositor *compositor, int *argc, char *argv[],
817 struct weston_config *config,
818 struct fbdev_parameters *param)
Philip Withnall4f499172013-02-02 12:02:32 +0000819{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300820 struct fbdev_backend *backend;
Rob Bradford2387fde2013-05-31 18:09:57 +0100821 const char *seat_id = default_seat;
Philip Withnall4f499172013-02-02 12:02:32 +0000822 uint32_t key;
823
824 weston_log("initializing fbdev backend\n");
825
Giulio Camuffo954f1832014-10-11 18:27:30 +0300826 backend = zalloc(sizeof *backend);
827 if (backend == NULL)
Philip Withnall4f499172013-02-02 12:02:32 +0000828 return NULL;
829
Giulio Camuffo954f1832014-10-11 18:27:30 +0300830 backend->compositor = compositor;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400831 if (weston_compositor_set_presentation_clock_software(
Giulio Camuffo954f1832014-10-11 18:27:30 +0300832 compositor) < 0)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400833 goto out_compositor;
834
Giulio Camuffo954f1832014-10-11 18:27:30 +0300835 backend->udev = udev_new();
836 if (backend->udev == NULL) {
Philip Withnall4f499172013-02-02 12:02:32 +0000837 weston_log("Failed to initialize udev context.\n");
838 goto out_compositor;
839 }
840
841 /* Set up the TTY. */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300842 backend->session_listener.notify = session_notify;
843 wl_signal_add(&compositor->session_signal,
844 &backend->session_listener);
845 compositor->launcher =
846 weston_launcher_connect(compositor, param->tty, "seat0", false);
847 if (!compositor->launcher) {
David Herrmann1641d142013-10-15 14:29:57 +0200848 weston_log("fatal: fbdev backend should be run "
849 "using weston-launch binary or as root\n");
Philip Withnall4f499172013-02-02 12:02:32 +0000850 goto out_udev;
851 }
852
Giulio Camuffo954f1832014-10-11 18:27:30 +0300853 backend->base.destroy = fbdev_backend_destroy;
854 backend->base.restore = fbdev_restore;
Philip Withnall4f499172013-02-02 12:02:32 +0000855
Giulio Camuffo954f1832014-10-11 18:27:30 +0300856 backend->prev_state = WESTON_COMPOSITOR_ACTIVE;
857 backend->use_pixman = !param->use_gl;
Philip Withnall4f499172013-02-02 12:02:32 +0000858
859 for (key = KEY_F1; key < KEY_F9; key++)
Giulio Camuffo954f1832014-10-11 18:27:30 +0300860 weston_compositor_add_key_binding(compositor, key,
Philip Withnall4f499172013-02-02 12:02:32 +0000861 MODIFIER_CTRL | MODIFIER_ALT,
862 switch_vt_binding,
863 compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300864 if (backend->use_pixman) {
865 if (pixman_renderer_init(compositor) < 0)
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700866 goto out_launcher;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300867 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300868 gl_renderer = weston_load_module("gl-renderer.so",
869 "gl_renderer_interface");
870 if (!gl_renderer) {
871 weston_log("could not load gl renderer\n");
872 goto out_launcher;
873 }
874
Giulio Camuffo954f1832014-10-11 18:27:30 +0300875 if (gl_renderer->create(compositor, NO_EGL_PLATFORM,
Jonny Lamb74eed312015-03-24 13:12:04 +0100876 EGL_DEFAULT_DISPLAY,
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300877 gl_renderer->opaque_attribs,
Derek Foremane76f1852015-05-15 12:12:39 -0500878 NULL, 0) < 0) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300879 weston_log("gl_renderer_create failed.\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700880 goto out_launcher;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300881 }
882 }
Philip Withnall4f499172013-02-02 12:02:32 +0000883
Giulio Camuffo954f1832014-10-11 18:27:30 +0300884 if (fbdev_output_create(backend, param->device) < 0)
Dawid Gajownik82d49252015-07-31 00:02:28 -0300885 goto out_launcher;
Philip Withnall4f499172013-02-02 12:02:32 +0000886
Giulio Camuffo954f1832014-10-11 18:27:30 +0300887 udev_input_init(&backend->input, compositor, backend->udev, seat_id);
Philip Withnall4f499172013-02-02 12:02:32 +0000888
Giulio Camuffo954f1832014-10-11 18:27:30 +0300889 compositor->backend = &backend->base;
890 return backend;
Philip Withnall4f499172013-02-02 12:02:32 +0000891
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700892out_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300893 weston_launcher_destroy(compositor->launcher);
Philip Withnall4f499172013-02-02 12:02:32 +0000894
895out_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300896 udev_unref(backend->udev);
Philip Withnall4f499172013-02-02 12:02:32 +0000897
898out_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300899 weston_compositor_shutdown(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300900 free(backend);
Philip Withnall4f499172013-02-02 12:02:32 +0000901
902 return NULL;
903}
904
Giulio Camuffo954f1832014-10-11 18:27:30 +0300905WL_EXPORT int
906backend_init(struct weston_compositor *compositor, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -0400907 struct weston_config *config)
Philip Withnall4f499172013-02-02 12:02:32 +0000908{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300909 struct fbdev_backend *b;
Philip Withnall4f499172013-02-02 12:02:32 +0000910 /* TODO: Ideally, available frame buffers should be enumerated using
911 * udev, rather than passing a device node in as a parameter. */
912 struct fbdev_parameters param = {
913 .tty = 0, /* default to current tty */
914 .device = "/dev/fb0", /* default frame buffer */
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300915 .use_gl = 0,
Philip Withnall4f499172013-02-02 12:02:32 +0000916 };
917
918 const struct weston_option fbdev_options[] = {
919 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
920 { WESTON_OPTION_STRING, "device", 0, &param.device },
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300921 { WESTON_OPTION_BOOLEAN, "use-gl", 0, &param.use_gl },
Philip Withnall4f499172013-02-02 12:02:32 +0000922 };
923
924 parse_options(fbdev_options, ARRAY_LENGTH(fbdev_options), argc, argv);
925
Giulio Camuffo954f1832014-10-11 18:27:30 +0300926 b = fbdev_backend_create(compositor, argc, argv, config, &param);
927 if (b == NULL)
928 return -1;
929 return 0;
Philip Withnall4f499172013-02-02 12:02:32 +0000930}