blob: f7782d8559ec9a355f31346b0eb4677cf1c171bd [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;
Philip Withnall4f499172013-02-02 12:02:32 +000093 uint8_t depth;
94};
95
Philip Withnall4f499172013-02-02 12:02:32 +000096struct fbdev_parameters {
97 int tty;
98 char *device;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +030099 int use_gl;
Philip Withnall4f499172013-02-02 12:02:32 +0000100};
101
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300102struct gl_renderer_interface *gl_renderer;
103
Kristian Høgsberg7e597f22013-02-18 16:35:26 -0500104static const char default_seat[] = "seat0";
105
Philip Withnall4f499172013-02-02 12:02:32 +0000106static inline struct fbdev_output *
107to_fbdev_output(struct weston_output *base)
108{
109 return container_of(base, struct fbdev_output, base);
110}
111
Giulio Camuffo954f1832014-10-11 18:27:30 +0300112static inline struct fbdev_backend *
113to_fbdev_backend(struct weston_compositor *base)
Philip Withnall4f499172013-02-02 12:02:32 +0000114{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300115 return container_of(base->backend, struct fbdev_backend, base);
Philip Withnall4f499172013-02-02 12:02:32 +0000116}
117
118static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200119fbdev_output_start_repaint_loop(struct weston_output *output)
120{
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400121 struct timespec ts;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200122
Pekka Paalanen662f3842015-03-18 12:17:26 +0200123 weston_compositor_read_presentation_clock(output->compositor, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200124 weston_output_finish_frame(output, &ts, PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200125}
126
127static void
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300128fbdev_output_repaint_pixman(struct weston_output *base, pixman_region32_t *damage)
Philip Withnall4f499172013-02-02 12:02:32 +0000129{
130 struct fbdev_output *output = to_fbdev_output(base);
131 struct weston_compositor *ec = output->base.compositor;
Philip Withnall4f499172013-02-02 12:02:32 +0000132
133 /* Repaint the damaged region onto the back buffer. */
Sjoerd Simonsc112e0c2015-12-04 19:20:12 -0600134 pixman_renderer_output_set_buffer(base, output->hw_surface);
Philip Withnall4f499172013-02-02 12:02:32 +0000135 ec->renderer->repaint_output(base, damage);
136
Philip Withnall4f499172013-02-02 12:02:32 +0000137 /* Update the damage region. */
138 pixman_region32_subtract(&ec->primary_plane.damage,
139 &ec->primary_plane.damage, damage);
140
141 /* Schedule the end of the frame. We do not sync this to the frame
142 * buffer clock because users who want that should be using the DRM
143 * compositor. FBIO_WAITFORVSYNC blocks and FB_ACTIVATE_VBL requires
144 * panning, which is broken in most kernel drivers.
145 *
146 * Finish the frame synchronised to the specified refresh rate. The
147 * refresh rate is given in mHz and the interval in ms. */
148 wl_event_source_timer_update(output->finish_frame_timer,
149 1000000 / output->mode.refresh);
150}
151
David Herrmann1edf44c2013-10-22 17:11:26 +0200152static int
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300153fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage)
154{
155 struct fbdev_output *output = to_fbdev_output(base);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300156 struct fbdev_backend *fbb = output->backend;
157 struct weston_compositor *ec = fbb->compositor;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300158
Giulio Camuffo954f1832014-10-11 18:27:30 +0300159 if (fbb->use_pixman) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300160 fbdev_output_repaint_pixman(base,damage);
161 } else {
162 ec->renderer->repaint_output(base, damage);
163 /* Update the damage region. */
164 pixman_region32_subtract(&ec->primary_plane.damage,
165 &ec->primary_plane.damage, damage);
166
167 wl_event_source_timer_update(output->finish_frame_timer,
168 1000000 / output->mode.refresh);
169 }
David Herrmann1edf44c2013-10-22 17:11:26 +0200170
171 return 0;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300172}
173
Philip Withnall4f499172013-02-02 12:02:32 +0000174static int
175finish_frame_handler(void *data)
176{
177 struct fbdev_output *output = data;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200178 struct timespec ts;
Philip Withnall4f499172013-02-02 12:02:32 +0000179
Pekka Paalanen662f3842015-03-18 12:17:26 +0200180 weston_compositor_read_presentation_clock(output->base.compositor, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200181 weston_output_finish_frame(&output->base, &ts, 0);
Philip Withnall4f499172013-02-02 12:02:32 +0000182
183 return 1;
184}
185
186static pixman_format_code_t
187calculate_pixman_format(struct fb_var_screeninfo *vinfo,
188 struct fb_fix_screeninfo *finfo)
189{
190 /* Calculate the pixman format supported by the frame buffer from the
191 * buffer's metadata. Return 0 if no known pixman format is supported
192 * (since this has depth 0 it's guaranteed to not conflict with any
193 * actual pixman format).
194 *
195 * Documentation on the vinfo and finfo structures:
196 * http://www.mjmwired.net/kernel/Documentation/fb/api.txt
197 *
198 * TODO: Try a bit harder to support other formats, including setting
199 * the preferred format in the hardware. */
200 int type;
201
202 weston_log("Calculating pixman format from:\n"
203 STAMP_SPACE " - type: %i (aux: %i)\n"
204 STAMP_SPACE " - visual: %i\n"
205 STAMP_SPACE " - bpp: %i (grayscale: %i)\n"
206 STAMP_SPACE " - red: offset: %i, length: %i, MSB: %i\n"
207 STAMP_SPACE " - green: offset: %i, length: %i, MSB: %i\n"
208 STAMP_SPACE " - blue: offset: %i, length: %i, MSB: %i\n"
209 STAMP_SPACE " - transp: offset: %i, length: %i, MSB: %i\n",
210 finfo->type, finfo->type_aux, finfo->visual,
211 vinfo->bits_per_pixel, vinfo->grayscale,
212 vinfo->red.offset, vinfo->red.length, vinfo->red.msb_right,
213 vinfo->green.offset, vinfo->green.length,
214 vinfo->green.msb_right,
215 vinfo->blue.offset, vinfo->blue.length,
216 vinfo->blue.msb_right,
217 vinfo->transp.offset, vinfo->transp.length,
218 vinfo->transp.msb_right);
219
220 /* We only handle packed formats at the moment. */
221 if (finfo->type != FB_TYPE_PACKED_PIXELS)
222 return 0;
223
224 /* We only handle true-colour frame buffers at the moment. */
Marc Chalainffbddff2013-09-03 16:47:43 +0200225 switch(finfo->visual) {
226 case FB_VISUAL_TRUECOLOR:
227 case FB_VISUAL_DIRECTCOLOR:
228 if (vinfo->grayscale != 0)
229 return 0;
230 break;
231 default:
232 return 0;
233 }
Philip Withnall4f499172013-02-02 12:02:32 +0000234
235 /* We only support formats with MSBs on the left. */
236 if (vinfo->red.msb_right != 0 || vinfo->green.msb_right != 0 ||
237 vinfo->blue.msb_right != 0)
238 return 0;
239
240 /* Work out the format type from the offsets. We only support RGBA and
241 * ARGB at the moment. */
242 type = PIXMAN_TYPE_OTHER;
243
244 if ((vinfo->transp.offset >= vinfo->red.offset ||
245 vinfo->transp.length == 0) &&
246 vinfo->red.offset >= vinfo->green.offset &&
247 vinfo->green.offset >= vinfo->blue.offset)
248 type = PIXMAN_TYPE_ARGB;
249 else if (vinfo->red.offset >= vinfo->green.offset &&
250 vinfo->green.offset >= vinfo->blue.offset &&
251 vinfo->blue.offset >= vinfo->transp.offset)
252 type = PIXMAN_TYPE_RGBA;
253
254 if (type == PIXMAN_TYPE_OTHER)
255 return 0;
256
257 /* Build the format. */
258 return PIXMAN_FORMAT(vinfo->bits_per_pixel, type,
259 vinfo->transp.length,
260 vinfo->red.length,
261 vinfo->green.length,
262 vinfo->blue.length);
263}
264
265static int
266calculate_refresh_rate(struct fb_var_screeninfo *vinfo)
267{
268 uint64_t quot;
269
270 /* Calculate monitor refresh rate. Default is 60 Hz. Units are mHz. */
271 quot = (vinfo->upper_margin + vinfo->lower_margin + vinfo->yres);
272 quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres);
273 quot *= vinfo->pixclock;
274
275 if (quot > 0) {
276 uint64_t refresh_rate;
277
278 refresh_rate = 1000000000000000LLU / quot;
279 if (refresh_rate > 200000)
280 refresh_rate = 200000; /* cap at 200 Hz */
281
282 return refresh_rate;
283 }
284
285 return 60 * 1000; /* default to 60 Hz */
286}
287
288static int
289fbdev_query_screen_info(struct fbdev_output *output, int fd,
290 struct fbdev_screeninfo *info)
291{
292 struct fb_var_screeninfo varinfo;
293 struct fb_fix_screeninfo fixinfo;
294
295 /* Probe the device for screen information. */
296 if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) < 0 ||
297 ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
298 return -1;
299 }
300
301 /* Store the pertinent data. */
302 info->x_resolution = varinfo.xres;
303 info->y_resolution = varinfo.yres;
304 info->width_mm = varinfo.width;
305 info->height_mm = varinfo.height;
306 info->bits_per_pixel = varinfo.bits_per_pixel;
307
308 info->buffer_length = fixinfo.smem_len;
309 info->line_length = fixinfo.line_length;
Derek Foreman61793382015-09-02 13:45:20 -0500310 strncpy(info->id, fixinfo.id, sizeof(info->id));
Bryce Harrington44bbdd02015-09-23 17:39:05 -0700311 info->id[sizeof(info->id)-1] = '\0';
Philip Withnall4f499172013-02-02 12:02:32 +0000312
313 info->pixel_format = calculate_pixman_format(&varinfo, &fixinfo);
314 info->refresh_rate = calculate_refresh_rate(&varinfo);
315
316 if (info->pixel_format == 0) {
317 weston_log("Frame buffer uses an unsupported format.\n");
318 return -1;
319 }
320
321 return 1;
322}
323
324static int
325fbdev_set_screen_info(struct fbdev_output *output, int fd,
326 struct fbdev_screeninfo *info)
327{
328 struct fb_var_screeninfo varinfo;
329
330 /* Grab the current screen information. */
331 if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
332 return -1;
333 }
334
335 /* Update the information. */
336 varinfo.xres = info->x_resolution;
337 varinfo.yres = info->y_resolution;
338 varinfo.width = info->width_mm;
339 varinfo.height = info->height_mm;
340 varinfo.bits_per_pixel = info->bits_per_pixel;
341
342 /* Try to set up an ARGB (x8r8g8b8) pixel format. */
343 varinfo.grayscale = 0;
344 varinfo.transp.offset = 24;
345 varinfo.transp.length = 0;
346 varinfo.transp.msb_right = 0;
347 varinfo.red.offset = 16;
348 varinfo.red.length = 8;
349 varinfo.red.msb_right = 0;
350 varinfo.green.offset = 8;
351 varinfo.green.length = 8;
352 varinfo.green.msb_right = 0;
353 varinfo.blue.offset = 0;
354 varinfo.blue.length = 8;
355 varinfo.blue.msb_right = 0;
356
357 /* Set the device's screen information. */
358 if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
359 return -1;
360 }
361
362 return 1;
363}
364
365static void fbdev_frame_buffer_destroy(struct fbdev_output *output);
366
367/* Returns an FD for the frame buffer device. */
368static int
369fbdev_frame_buffer_open(struct fbdev_output *output, const char *fb_dev,
370 struct fbdev_screeninfo *screen_info)
371{
372 int fd = -1;
373
374 weston_log("Opening fbdev frame buffer.\n");
375
376 /* Open the frame buffer device. */
377 fd = open(fb_dev, O_RDWR | O_CLOEXEC);
378 if (fd < 0) {
379 weston_log("Failed to open frame buffer device ‘%s’: %s\n",
380 fb_dev, strerror(errno));
381 return -1;
382 }
383
384 /* Grab the screen info. */
385 if (fbdev_query_screen_info(output, fd, screen_info) < 0) {
386 weston_log("Failed to get frame buffer info: %s\n",
387 strerror(errno));
388
389 close(fd);
390 return -1;
391 }
392
393 return fd;
394}
395
396/* Closes the FD on success or failure. */
397static int
398fbdev_frame_buffer_map(struct fbdev_output *output, int fd)
399{
400 int retval = -1;
401
402 weston_log("Mapping fbdev frame buffer.\n");
403
404 /* Map the frame buffer. Write-only mode, since we don't want to read
405 * anything back (because it's slow). */
406 output->fb = mmap(NULL, output->fb_info.buffer_length,
407 PROT_WRITE, MAP_SHARED, fd, 0);
408 if (output->fb == MAP_FAILED) {
409 weston_log("Failed to mmap frame buffer: %s\n",
410 strerror(errno));
411 goto out_close;
412 }
413
414 /* Create a pixman image to wrap the memory mapped frame buffer. */
415 output->hw_surface =
416 pixman_image_create_bits(output->fb_info.pixel_format,
417 output->fb_info.x_resolution,
418 output->fb_info.y_resolution,
419 output->fb,
420 output->fb_info.line_length);
421 if (output->hw_surface == NULL) {
422 weston_log("Failed to create surface for frame buffer.\n");
423 goto out_unmap;
424 }
425
426 /* Success! */
427 retval = 0;
428
429out_unmap:
430 if (retval != 0 && output->fb != NULL)
431 fbdev_frame_buffer_destroy(output);
432
433out_close:
434 if (fd >= 0)
435 close(fd);
436
437 return retval;
438}
439
440static void
441fbdev_frame_buffer_destroy(struct fbdev_output *output)
442{
443 weston_log("Destroying fbdev frame buffer.\n");
444
445 if (munmap(output->fb, output->fb_info.buffer_length) < 0)
446 weston_log("Failed to munmap frame buffer: %s\n",
447 strerror(errno));
448
449 output->fb = NULL;
450}
451
452static void fbdev_output_destroy(struct weston_output *base);
453static void fbdev_output_disable(struct weston_output *base);
454
455static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300456fbdev_output_create(struct fbdev_backend *backend,
Philip Withnall4f499172013-02-02 12:02:32 +0000457 const char *device)
458{
459 struct fbdev_output *output;
Derek Foreman44ed70b2015-03-17 13:22:37 -0500460 struct weston_config_section *section;
Philip Withnall4f499172013-02-02 12:02:32 +0000461 int fb_fd;
Philip Withnall4f499172013-02-02 12:02:32 +0000462 struct wl_event_loop *loop;
Derek Foreman44ed70b2015-03-17 13:22:37 -0500463 uint32_t config_transform;
464 char *s;
Philip Withnall4f499172013-02-02 12:02:32 +0000465
466 weston_log("Creating fbdev output.\n");
467
Bryce Harringtonde16d892014-11-20 22:21:57 -0800468 output = zalloc(sizeof *output);
469 if (output == NULL)
Philip Withnall4f499172013-02-02 12:02:32 +0000470 return -1;
471
Giulio Camuffo954f1832014-10-11 18:27:30 +0300472 output->backend = backend;
Philip Withnall4f499172013-02-02 12:02:32 +0000473 output->device = device;
474
475 /* Create the frame buffer. */
476 fb_fd = fbdev_frame_buffer_open(output, device, &output->fb_info);
477 if (fb_fd < 0) {
478 weston_log("Creating frame buffer failed.\n");
479 goto out_free;
480 }
Giulio Camuffo954f1832014-10-11 18:27:30 +0300481 if (backend->use_pixman) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300482 if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
483 weston_log("Mapping frame buffer failed.\n");
484 goto out_free;
485 }
Kristian Høgsberg8ac6a2d2013-10-09 09:59:06 -0700486 } else {
487 close(fb_fd);
Philip Withnall4f499172013-02-02 12:02:32 +0000488 }
489
Jonas Ådahle5a12252013-04-05 23:07:11 +0200490 output->base.start_repaint_loop = fbdev_output_start_repaint_loop;
Philip Withnall4f499172013-02-02 12:02:32 +0000491 output->base.repaint = fbdev_output_repaint;
492 output->base.destroy = fbdev_output_destroy;
Philip Withnall4f499172013-02-02 12:02:32 +0000493
494 /* only one static mode in list */
495 output->mode.flags =
496 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
497 output->mode.width = output->fb_info.x_resolution;
498 output->mode.height = output->fb_info.y_resolution;
499 output->mode.refresh = output->fb_info.refresh_rate;
500 wl_list_init(&output->base.mode_list);
501 wl_list_insert(&output->base.mode_list, &output->mode.link);
502
Hardeningff39efa2013-09-18 23:56:35 +0200503 output->base.current_mode = &output->mode;
Philip Withnall4f499172013-02-02 12:02:32 +0000504 output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
505 output->base.make = "unknown";
506 output->base.model = output->fb_info.id;
Derek Foremane516c3b2015-03-17 13:22:34 -0500507 output->base.name = strdup("fbdev");
Philip Withnall4f499172013-02-02 12:02:32 +0000508
Giulio Camuffo954f1832014-10-11 18:27:30 +0300509 section = weston_config_get_section(backend->compositor->config,
Derek Foreman44ed70b2015-03-17 13:22:37 -0500510 "output", "name",
511 output->base.name);
512 weston_config_section_get_string(section, "transform", &s, "normal");
513 if (weston_parse_transform(s, &config_transform) < 0)
514 weston_log("Invalid transform \"%s\" for output %s\n",
515 s, output->base.name);
516 free(s);
517
Giulio Camuffo954f1832014-10-11 18:27:30 +0300518 weston_output_init(&output->base, backend->compositor,
Philip Withnall4f499172013-02-02 12:02:32 +0000519 0, 0, output->fb_info.width_mm,
520 output->fb_info.height_mm,
Derek Foreman44ed70b2015-03-17 13:22:37 -0500521 config_transform,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200522 1);
Philip Withnall4f499172013-02-02 12:02:32 +0000523
Giulio Camuffo954f1832014-10-11 18:27:30 +0300524 if (backend->use_pixman) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300525 if (pixman_renderer_output_create(&output->base) < 0)
Sjoerd Simonsc112e0c2015-12-04 19:20:12 -0600526 goto out_hw_surface;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300527 } else {
528 setenv("HYBRIS_EGLPLATFORM", "wayland", 1);
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300529 if (gl_renderer->output_create(&output->base,
Jonny Lamb671148f2015-03-20 15:26:52 +0100530 (EGLNativeWindowType)NULL, NULL,
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000531 gl_renderer->opaque_attribs,
Derek Foremane76f1852015-05-15 12:12:39 -0500532 NULL, 0) < 0) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300533 weston_log("gl_renderer_output_create failed.\n");
Sjoerd Simonsc112e0c2015-12-04 19:20:12 -0600534 goto out_hw_surface;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300535 }
536 }
537
Giulio Camuffo954f1832014-10-11 18:27:30 +0300538 loop = wl_display_get_event_loop(backend->compositor->wl_display);
Philip Withnall4f499172013-02-02 12:02:32 +0000539 output->finish_frame_timer =
540 wl_event_loop_add_timer(loop, finish_frame_handler, output);
541
Giulio Camuffo954f1832014-10-11 18:27:30 +0300542 weston_compositor_add_output(backend->compositor, &output->base);
Philip Withnall4f499172013-02-02 12:02:32 +0000543
544 weston_log("fbdev output %d×%d px\n",
545 output->mode.width, output->mode.height);
546 weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
547 output->mode.refresh / 1000);
548
549 return 0;
550
Philip Withnall4f499172013-02-02 12:02:32 +0000551out_hw_surface:
Philip Withnall4f499172013-02-02 12:02:32 +0000552 pixman_image_unref(output->hw_surface);
553 output->hw_surface = NULL;
554 weston_output_destroy(&output->base);
555 fbdev_frame_buffer_destroy(output);
556out_free:
557 free(output);
558
559 return -1;
560}
561
562static void
563fbdev_output_destroy(struct weston_output *base)
564{
565 struct fbdev_output *output = to_fbdev_output(base);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300566 struct fbdev_backend *backend = output->backend;
Philip Withnall4f499172013-02-02 12:02:32 +0000567
568 weston_log("Destroying fbdev output.\n");
569
570 /* Close the frame buffer. */
571 fbdev_output_disable(base);
572
Giulio Camuffo954f1832014-10-11 18:27:30 +0300573 if (backend->use_pixman) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300574 if (base->renderer_state != NULL)
575 pixman_renderer_output_destroy(base);
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300576 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300577 gl_renderer->output_destroy(base);
Philip Withnall4f499172013-02-02 12:02:32 +0000578 }
579
580 /* Remove the output. */
Philip Withnall4f499172013-02-02 12:02:32 +0000581 weston_output_destroy(&output->base);
582
583 free(output);
584}
585
586/* strcmp()-style return values. */
587static int
588compare_screen_info (const struct fbdev_screeninfo *a,
589 const struct fbdev_screeninfo *b)
590{
591 if (a->x_resolution == b->x_resolution &&
592 a->y_resolution == b->y_resolution &&
593 a->width_mm == b->width_mm &&
594 a->height_mm == b->height_mm &&
595 a->bits_per_pixel == b->bits_per_pixel &&
596 a->pixel_format == b->pixel_format &&
597 a->refresh_rate == b->refresh_rate)
598 return 0;
599
600 return 1;
601}
602
603static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300604fbdev_output_reenable(struct fbdev_backend *backend,
Philip Withnall4f499172013-02-02 12:02:32 +0000605 struct weston_output *base)
606{
607 struct fbdev_output *output = to_fbdev_output(base);
608 struct fbdev_screeninfo new_screen_info;
609 int fb_fd;
Rob Bradfordf8ef42f2013-07-26 16:29:38 +0100610 const char *device;
Philip Withnall4f499172013-02-02 12:02:32 +0000611
612 weston_log("Re-enabling fbdev output.\n");
613
614 /* Create the frame buffer. */
615 fb_fd = fbdev_frame_buffer_open(output, output->device,
616 &new_screen_info);
617 if (fb_fd < 0) {
618 weston_log("Creating frame buffer failed.\n");
619 goto err;
620 }
621
622 /* Check whether the frame buffer details have changed since we were
623 * disabled. */
624 if (compare_screen_info (&output->fb_info, &new_screen_info) != 0) {
625 /* Perform a mode-set to restore the old mode. */
626 if (fbdev_set_screen_info(output, fb_fd,
627 &output->fb_info) < 0) {
628 weston_log("Failed to restore mode settings. "
629 "Attempting to re-open output anyway.\n");
630 }
631
Rob Bradford581b3fd2013-07-26 16:29:39 +0100632 close(fb_fd);
633
Philip Withnall4f499172013-02-02 12:02:32 +0000634 /* Remove and re-add the output so that resources depending on
635 * the frame buffer X/Y resolution (such as the shadow buffer)
636 * are re-initialised. */
Rob Bradfordf8ef42f2013-07-26 16:29:38 +0100637 device = output->device;
Philip Withnall4f499172013-02-02 12:02:32 +0000638 fbdev_output_destroy(base);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300639 fbdev_output_create(backend, device);
Philip Withnall4f499172013-02-02 12:02:32 +0000640
641 return 0;
642 }
643
644 /* Map the device if it has the same details as before. */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300645 if (backend->use_pixman) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300646 if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
647 weston_log("Mapping frame buffer failed.\n");
648 goto err;
649 }
Philip Withnall4f499172013-02-02 12:02:32 +0000650 }
651
652 return 0;
653
654err:
655 return -1;
656}
657
658/* NOTE: This leaves output->fb_info populated, caching data so that if
659 * fbdev_output_reenable() is called again, it can determine whether a mode-set
660 * is needed. */
661static void
662fbdev_output_disable(struct weston_output *base)
663{
664 struct fbdev_output *output = to_fbdev_output(base);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300665 struct fbdev_backend *backend = output->backend;
Philip Withnall4f499172013-02-02 12:02:32 +0000666
667 weston_log("Disabling fbdev output.\n");
668
Giulio Camuffo954f1832014-10-11 18:27:30 +0300669 if ( ! backend->use_pixman) return;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300670
Philip Withnall4f499172013-02-02 12:02:32 +0000671 if (output->hw_surface != NULL) {
672 pixman_image_unref(output->hw_surface);
673 output->hw_surface = NULL;
674 }
675
676 fbdev_frame_buffer_destroy(output);
677}
678
679static void
Giulio Camuffo954f1832014-10-11 18:27:30 +0300680fbdev_backend_destroy(struct weston_compositor *base)
Philip Withnall4f499172013-02-02 12:02:32 +0000681{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300682 struct fbdev_backend *backend = to_fbdev_backend(base);
Philip Withnall4f499172013-02-02 12:02:32 +0000683
Giulio Camuffo954f1832014-10-11 18:27:30 +0300684 udev_input_destroy(&backend->input);
Philip Withnall4f499172013-02-02 12:02:32 +0000685
686 /* Destroy the output. */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300687 weston_compositor_shutdown(base);
Philip Withnall4f499172013-02-02 12:02:32 +0000688
689 /* Chain up. */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300690 weston_launcher_destroy(base->launcher);
Philip Withnall4f499172013-02-02 12:02:32 +0000691
Giulio Camuffo954f1832014-10-11 18:27:30 +0300692 free(backend);
Philip Withnall4f499172013-02-02 12:02:32 +0000693}
694
695static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700696session_notify(struct wl_listener *listener, void *data)
Philip Withnall4f499172013-02-02 12:02:32 +0000697{
Pekka Paalanen3f897942015-08-19 13:52:47 +0300698 struct weston_compositor *compositor = data;
699 struct fbdev_backend *backend = to_fbdev_backend(compositor);
Philip Withnall4f499172013-02-02 12:02:32 +0000700 struct weston_output *output;
701
Giulio Camuffo954f1832014-10-11 18:27:30 +0300702 if (compositor->session_active) {
Philip Withnall4f499172013-02-02 12:02:32 +0000703 weston_log("entering VT\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +0300704 compositor->state = backend->prev_state;
Philip Withnall4f499172013-02-02 12:02:32 +0000705
Giulio Camuffo954f1832014-10-11 18:27:30 +0300706 wl_list_for_each(output, &compositor->output_list, link) {
707 fbdev_output_reenable(backend, output);
Philip Withnall4f499172013-02-02 12:02:32 +0000708 }
709
Giulio Camuffo954f1832014-10-11 18:27:30 +0300710 weston_compositor_damage_all(compositor);
Philip Withnall4f499172013-02-02 12:02:32 +0000711
Giulio Camuffo954f1832014-10-11 18:27:30 +0300712 udev_input_enable(&backend->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700713 } else {
Philip Withnall4f499172013-02-02 12:02:32 +0000714 weston_log("leaving VT\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +0300715 udev_input_disable(&backend->input);
Philip Withnall4f499172013-02-02 12:02:32 +0000716
Giulio Camuffo954f1832014-10-11 18:27:30 +0300717 wl_list_for_each(output, &compositor->output_list, link) {
Philip Withnall4f499172013-02-02 12:02:32 +0000718 fbdev_output_disable(output);
719 }
720
Giulio Camuffo954f1832014-10-11 18:27:30 +0300721 backend->prev_state = compositor->state;
722 weston_compositor_offscreen(compositor);
Philip Withnall4f499172013-02-02 12:02:32 +0000723
724 /* If we have a repaint scheduled (from the idle handler), make
725 * sure we cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +0100726 * vt switched away. The OFFSCREEN state will prevent
Bryce Harringtonc2be8572015-12-11 13:11:37 -0800727 * further attempts at repainting. When we switch
Philip Withnall4f499172013-02-02 12:02:32 +0000728 * back, we schedule a repaint, which will process
729 * pending frame callbacks. */
730
731 wl_list_for_each(output,
Giulio Camuffo954f1832014-10-11 18:27:30 +0300732 &compositor->output_list, link) {
Philip Withnall4f499172013-02-02 12:02:32 +0000733 output->repaint_needed = 0;
734 }
nerdopolis38946702014-12-03 15:53:03 +0000735 }
Philip Withnall4f499172013-02-02 12:02:32 +0000736}
737
738static void
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700739fbdev_restore(struct weston_compositor *compositor)
Philip Withnall4f499172013-02-02 12:02:32 +0000740{
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700741 weston_launcher_restore(compositor->launcher);
Philip Withnall4f499172013-02-02 12:02:32 +0000742}
743
744static void
Derek Foreman8ae2db52015-07-15 13:00:36 -0500745switch_vt_binding(struct weston_keyboard *keyboard, uint32_t time,
746 uint32_t key, void *data)
Philip Withnall4f499172013-02-02 12:02:32 +0000747{
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700748 struct weston_compositor *compositor = data;
Philip Withnall4f499172013-02-02 12:02:32 +0000749
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700750 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Philip Withnall4f499172013-02-02 12:02:32 +0000751}
752
Giulio Camuffo954f1832014-10-11 18:27:30 +0300753static struct fbdev_backend *
754fbdev_backend_create(struct weston_compositor *compositor, int *argc, char *argv[],
755 struct weston_config *config,
756 struct fbdev_parameters *param)
Philip Withnall4f499172013-02-02 12:02:32 +0000757{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300758 struct fbdev_backend *backend;
Rob Bradford2387fde2013-05-31 18:09:57 +0100759 const char *seat_id = default_seat;
Philip Withnall4f499172013-02-02 12:02:32 +0000760 uint32_t key;
761
762 weston_log("initializing fbdev backend\n");
763
Giulio Camuffo954f1832014-10-11 18:27:30 +0300764 backend = zalloc(sizeof *backend);
765 if (backend == NULL)
Philip Withnall4f499172013-02-02 12:02:32 +0000766 return NULL;
767
Giulio Camuffo954f1832014-10-11 18:27:30 +0300768 backend->compositor = compositor;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400769 if (weston_compositor_set_presentation_clock_software(
Giulio Camuffo954f1832014-10-11 18:27:30 +0300770 compositor) < 0)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400771 goto out_compositor;
772
Giulio Camuffo954f1832014-10-11 18:27:30 +0300773 backend->udev = udev_new();
774 if (backend->udev == NULL) {
Philip Withnall4f499172013-02-02 12:02:32 +0000775 weston_log("Failed to initialize udev context.\n");
776 goto out_compositor;
777 }
778
779 /* Set up the TTY. */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300780 backend->session_listener.notify = session_notify;
781 wl_signal_add(&compositor->session_signal,
782 &backend->session_listener);
783 compositor->launcher =
784 weston_launcher_connect(compositor, param->tty, "seat0", false);
785 if (!compositor->launcher) {
David Herrmann1641d142013-10-15 14:29:57 +0200786 weston_log("fatal: fbdev backend should be run "
787 "using weston-launch binary or as root\n");
Philip Withnall4f499172013-02-02 12:02:32 +0000788 goto out_udev;
789 }
790
Giulio Camuffo954f1832014-10-11 18:27:30 +0300791 backend->base.destroy = fbdev_backend_destroy;
792 backend->base.restore = fbdev_restore;
Philip Withnall4f499172013-02-02 12:02:32 +0000793
Giulio Camuffo954f1832014-10-11 18:27:30 +0300794 backend->prev_state = WESTON_COMPOSITOR_ACTIVE;
795 backend->use_pixman = !param->use_gl;
Philip Withnall4f499172013-02-02 12:02:32 +0000796
797 for (key = KEY_F1; key < KEY_F9; key++)
Giulio Camuffo954f1832014-10-11 18:27:30 +0300798 weston_compositor_add_key_binding(compositor, key,
Philip Withnall4f499172013-02-02 12:02:32 +0000799 MODIFIER_CTRL | MODIFIER_ALT,
800 switch_vt_binding,
801 compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300802 if (backend->use_pixman) {
803 if (pixman_renderer_init(compositor) < 0)
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700804 goto out_launcher;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300805 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300806 gl_renderer = weston_load_module("gl-renderer.so",
807 "gl_renderer_interface");
808 if (!gl_renderer) {
809 weston_log("could not load gl renderer\n");
810 goto out_launcher;
811 }
812
Giulio Camuffo954f1832014-10-11 18:27:30 +0300813 if (gl_renderer->create(compositor, NO_EGL_PLATFORM,
Jonny Lamb74eed312015-03-24 13:12:04 +0100814 EGL_DEFAULT_DISPLAY,
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300815 gl_renderer->opaque_attribs,
Derek Foremane76f1852015-05-15 12:12:39 -0500816 NULL, 0) < 0) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300817 weston_log("gl_renderer_create failed.\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700818 goto out_launcher;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300819 }
820 }
Philip Withnall4f499172013-02-02 12:02:32 +0000821
Giulio Camuffo954f1832014-10-11 18:27:30 +0300822 if (fbdev_output_create(backend, param->device) < 0)
Dawid Gajownik82d49252015-07-31 00:02:28 -0300823 goto out_launcher;
Philip Withnall4f499172013-02-02 12:02:32 +0000824
Giulio Camuffo954f1832014-10-11 18:27:30 +0300825 udev_input_init(&backend->input, compositor, backend->udev, seat_id);
Philip Withnall4f499172013-02-02 12:02:32 +0000826
Giulio Camuffo954f1832014-10-11 18:27:30 +0300827 compositor->backend = &backend->base;
828 return backend;
Philip Withnall4f499172013-02-02 12:02:32 +0000829
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700830out_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300831 weston_launcher_destroy(compositor->launcher);
Philip Withnall4f499172013-02-02 12:02:32 +0000832
833out_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300834 udev_unref(backend->udev);
Philip Withnall4f499172013-02-02 12:02:32 +0000835
836out_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300837 weston_compositor_shutdown(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300838 free(backend);
Philip Withnall4f499172013-02-02 12:02:32 +0000839
840 return NULL;
841}
842
Giulio Camuffo954f1832014-10-11 18:27:30 +0300843WL_EXPORT int
844backend_init(struct weston_compositor *compositor, int *argc, char *argv[],
Giulio Camuffo93daabb2015-10-17 19:24:14 +0300845 struct weston_config *config,
846 struct weston_backend_config *config_base)
Philip Withnall4f499172013-02-02 12:02:32 +0000847{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300848 struct fbdev_backend *b;
Philip Withnall4f499172013-02-02 12:02:32 +0000849 /* TODO: Ideally, available frame buffers should be enumerated using
850 * udev, rather than passing a device node in as a parameter. */
851 struct fbdev_parameters param = {
852 .tty = 0, /* default to current tty */
853 .device = "/dev/fb0", /* default frame buffer */
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300854 .use_gl = 0,
Philip Withnall4f499172013-02-02 12:02:32 +0000855 };
856
857 const struct weston_option fbdev_options[] = {
858 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
859 { WESTON_OPTION_STRING, "device", 0, &param.device },
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300860 { WESTON_OPTION_BOOLEAN, "use-gl", 0, &param.use_gl },
Philip Withnall4f499172013-02-02 12:02:32 +0000861 };
862
863 parse_options(fbdev_options, ARRAY_LENGTH(fbdev_options), argc, argv);
864
Giulio Camuffo954f1832014-10-11 18:27:30 +0300865 b = fbdev_backend_create(compositor, argc, argv, config, &param);
866 if (b == NULL)
867 return -1;
868 return 0;
Philip Withnall4f499172013-02-02 12:02:32 +0000869}