blob: ee762e312c59f3de8c4614d68b9639d849a8db6e [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"
Benoit Gschwind934e89a2016-04-27 23:56:42 +020047#include "compositor-fbdev.h"
Philip Withnall4f499172013-02-02 12:02:32 +000048#include "launcher-util.h"
49#include "pixman-renderer.h"
Peter Hutterer823ad332014-11-26 07:06:31 +100050#include "libinput-seat.h"
Adrian Negreanu4aa756d2013-09-06 15:16:09 +030051#include "gl-renderer.h"
Pekka Paalanenb00c79b2016-02-18 16:53:27 +020052#include "presentation-time-server-protocol.h"
Philip Withnall4f499172013-02-02 12:02:32 +000053
Giulio Camuffo954f1832014-10-11 18:27:30 +030054struct fbdev_backend {
55 struct weston_backend base;
56 struct weston_compositor *compositor;
Philip Withnall4f499172013-02-02 12:02:32 +000057 uint32_t prev_state;
58
59 struct udev *udev;
Rob Bradfordd355b802013-05-31 18:09:55 +010060 struct udev_input input;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +030061 int use_pixman;
Benoit Gschwind934e89a2016-04-27 23:56:42 +020062 uint32_t output_transform;
Kristian Høgsberg61741a22013-09-17 16:02:57 -070063 struct wl_listener session_listener;
Philip Withnall4f499172013-02-02 12:02:32 +000064};
65
66struct fbdev_screeninfo {
67 unsigned int x_resolution; /* pixels, visible area */
68 unsigned int y_resolution; /* pixels, visible area */
69 unsigned int width_mm; /* visible screen width in mm */
70 unsigned int height_mm; /* visible screen height in mm */
71 unsigned int bits_per_pixel;
72
73 size_t buffer_length; /* length of frame buffer memory in bytes */
74 size_t line_length; /* length of a line in bytes */
75 char id[16]; /* screen identifier */
76
77 pixman_format_code_t pixel_format; /* frame buffer pixel format */
78 unsigned int refresh_rate; /* Hertz */
79};
80
81struct fbdev_output {
Giulio Camuffo954f1832014-10-11 18:27:30 +030082 struct fbdev_backend *backend;
Philip Withnall4f499172013-02-02 12:02:32 +000083 struct weston_output base;
84
85 struct weston_mode mode;
86 struct wl_event_source *finish_frame_timer;
87
88 /* Frame buffer details. */
Pekka Paalanene5b56592016-04-28 15:12:25 +030089 char *device;
Philip Withnall4f499172013-02-02 12:02:32 +000090 struct fbdev_screeninfo fb_info;
91 void *fb; /* length is fb_info.buffer_length */
92
93 /* pixman details. */
94 pixman_image_t *hw_surface;
Philip Withnall4f499172013-02-02 12:02:32 +000095 uint8_t depth;
96};
97
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030098struct gl_renderer_interface *gl_renderer;
99
Kristian Høgsberg7e597f22013-02-18 16:35:26 -0500100static const char default_seat[] = "seat0";
101
Philip Withnall4f499172013-02-02 12:02:32 +0000102static inline struct fbdev_output *
103to_fbdev_output(struct weston_output *base)
104{
105 return container_of(base, struct fbdev_output, base);
106}
107
Giulio Camuffo954f1832014-10-11 18:27:30 +0300108static inline struct fbdev_backend *
109to_fbdev_backend(struct weston_compositor *base)
Philip Withnall4f499172013-02-02 12:02:32 +0000110{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300111 return container_of(base->backend, struct fbdev_backend, base);
Philip Withnall4f499172013-02-02 12:02:32 +0000112}
113
114static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200115fbdev_output_start_repaint_loop(struct weston_output *output)
116{
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400117 struct timespec ts;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200118
Pekka Paalanen662f3842015-03-18 12:17:26 +0200119 weston_compositor_read_presentation_clock(output->compositor, &ts);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200120 weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200121}
122
123static void
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300124fbdev_output_repaint_pixman(struct weston_output *base, pixman_region32_t *damage)
Philip Withnall4f499172013-02-02 12:02:32 +0000125{
126 struct fbdev_output *output = to_fbdev_output(base);
127 struct weston_compositor *ec = output->base.compositor;
Philip Withnall4f499172013-02-02 12:02:32 +0000128
129 /* Repaint the damaged region onto the back buffer. */
Sjoerd Simonsc112e0c2015-12-04 19:20:12 -0600130 pixman_renderer_output_set_buffer(base, output->hw_surface);
Philip Withnall4f499172013-02-02 12:02:32 +0000131 ec->renderer->repaint_output(base, damage);
132
Philip Withnall4f499172013-02-02 12:02:32 +0000133 /* Update the damage region. */
134 pixman_region32_subtract(&ec->primary_plane.damage,
135 &ec->primary_plane.damage, damage);
136
137 /* Schedule the end of the frame. We do not sync this to the frame
138 * buffer clock because users who want that should be using the DRM
139 * compositor. FBIO_WAITFORVSYNC blocks and FB_ACTIVATE_VBL requires
140 * panning, which is broken in most kernel drivers.
141 *
142 * Finish the frame synchronised to the specified refresh rate. The
143 * refresh rate is given in mHz and the interval in ms. */
144 wl_event_source_timer_update(output->finish_frame_timer,
145 1000000 / output->mode.refresh);
146}
147
David Herrmann1edf44c2013-10-22 17:11:26 +0200148static int
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300149fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage)
150{
151 struct fbdev_output *output = to_fbdev_output(base);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300152 struct fbdev_backend *fbb = output->backend;
153 struct weston_compositor *ec = fbb->compositor;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300154
Giulio Camuffo954f1832014-10-11 18:27:30 +0300155 if (fbb->use_pixman) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300156 fbdev_output_repaint_pixman(base,damage);
157 } else {
158 ec->renderer->repaint_output(base, damage);
159 /* Update the damage region. */
160 pixman_region32_subtract(&ec->primary_plane.damage,
161 &ec->primary_plane.damage, damage);
162
163 wl_event_source_timer_update(output->finish_frame_timer,
164 1000000 / output->mode.refresh);
165 }
David Herrmann1edf44c2013-10-22 17:11:26 +0200166
167 return 0;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300168}
169
Philip Withnall4f499172013-02-02 12:02:32 +0000170static int
171finish_frame_handler(void *data)
172{
173 struct fbdev_output *output = data;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200174 struct timespec ts;
Philip Withnall4f499172013-02-02 12:02:32 +0000175
Pekka Paalanen662f3842015-03-18 12:17:26 +0200176 weston_compositor_read_presentation_clock(output->base.compositor, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200177 weston_output_finish_frame(&output->base, &ts, 0);
Philip Withnall4f499172013-02-02 12:02:32 +0000178
179 return 1;
180}
181
182static pixman_format_code_t
183calculate_pixman_format(struct fb_var_screeninfo *vinfo,
184 struct fb_fix_screeninfo *finfo)
185{
186 /* Calculate the pixman format supported by the frame buffer from the
187 * buffer's metadata. Return 0 if no known pixman format is supported
188 * (since this has depth 0 it's guaranteed to not conflict with any
189 * actual pixman format).
190 *
191 * Documentation on the vinfo and finfo structures:
192 * http://www.mjmwired.net/kernel/Documentation/fb/api.txt
193 *
194 * TODO: Try a bit harder to support other formats, including setting
195 * the preferred format in the hardware. */
196 int type;
197
198 weston_log("Calculating pixman format from:\n"
199 STAMP_SPACE " - type: %i (aux: %i)\n"
200 STAMP_SPACE " - visual: %i\n"
201 STAMP_SPACE " - bpp: %i (grayscale: %i)\n"
202 STAMP_SPACE " - red: offset: %i, length: %i, MSB: %i\n"
203 STAMP_SPACE " - green: offset: %i, length: %i, MSB: %i\n"
204 STAMP_SPACE " - blue: offset: %i, length: %i, MSB: %i\n"
205 STAMP_SPACE " - transp: offset: %i, length: %i, MSB: %i\n",
206 finfo->type, finfo->type_aux, finfo->visual,
207 vinfo->bits_per_pixel, vinfo->grayscale,
208 vinfo->red.offset, vinfo->red.length, vinfo->red.msb_right,
209 vinfo->green.offset, vinfo->green.length,
210 vinfo->green.msb_right,
211 vinfo->blue.offset, vinfo->blue.length,
212 vinfo->blue.msb_right,
213 vinfo->transp.offset, vinfo->transp.length,
214 vinfo->transp.msb_right);
215
216 /* We only handle packed formats at the moment. */
217 if (finfo->type != FB_TYPE_PACKED_PIXELS)
218 return 0;
219
220 /* We only handle true-colour frame buffers at the moment. */
Marc Chalainffbddff2013-09-03 16:47:43 +0200221 switch(finfo->visual) {
222 case FB_VISUAL_TRUECOLOR:
223 case FB_VISUAL_DIRECTCOLOR:
224 if (vinfo->grayscale != 0)
225 return 0;
226 break;
227 default:
228 return 0;
229 }
Philip Withnall4f499172013-02-02 12:02:32 +0000230
231 /* We only support formats with MSBs on the left. */
232 if (vinfo->red.msb_right != 0 || vinfo->green.msb_right != 0 ||
233 vinfo->blue.msb_right != 0)
234 return 0;
235
236 /* Work out the format type from the offsets. We only support RGBA and
237 * ARGB at the moment. */
238 type = PIXMAN_TYPE_OTHER;
239
240 if ((vinfo->transp.offset >= vinfo->red.offset ||
241 vinfo->transp.length == 0) &&
242 vinfo->red.offset >= vinfo->green.offset &&
243 vinfo->green.offset >= vinfo->blue.offset)
244 type = PIXMAN_TYPE_ARGB;
245 else if (vinfo->red.offset >= vinfo->green.offset &&
246 vinfo->green.offset >= vinfo->blue.offset &&
247 vinfo->blue.offset >= vinfo->transp.offset)
248 type = PIXMAN_TYPE_RGBA;
249
250 if (type == PIXMAN_TYPE_OTHER)
251 return 0;
252
253 /* Build the format. */
254 return PIXMAN_FORMAT(vinfo->bits_per_pixel, type,
255 vinfo->transp.length,
256 vinfo->red.length,
257 vinfo->green.length,
258 vinfo->blue.length);
259}
260
261static int
262calculate_refresh_rate(struct fb_var_screeninfo *vinfo)
263{
264 uint64_t quot;
265
266 /* Calculate monitor refresh rate. Default is 60 Hz. Units are mHz. */
267 quot = (vinfo->upper_margin + vinfo->lower_margin + vinfo->yres);
268 quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres);
269 quot *= vinfo->pixclock;
270
271 if (quot > 0) {
272 uint64_t refresh_rate;
273
274 refresh_rate = 1000000000000000LLU / quot;
275 if (refresh_rate > 200000)
276 refresh_rate = 200000; /* cap at 200 Hz */
277
278 return refresh_rate;
279 }
280
281 return 60 * 1000; /* default to 60 Hz */
282}
283
284static int
285fbdev_query_screen_info(struct fbdev_output *output, int fd,
286 struct fbdev_screeninfo *info)
287{
288 struct fb_var_screeninfo varinfo;
289 struct fb_fix_screeninfo fixinfo;
290
291 /* Probe the device for screen information. */
292 if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) < 0 ||
293 ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
294 return -1;
295 }
296
297 /* Store the pertinent data. */
298 info->x_resolution = varinfo.xres;
299 info->y_resolution = varinfo.yres;
300 info->width_mm = varinfo.width;
301 info->height_mm = varinfo.height;
302 info->bits_per_pixel = varinfo.bits_per_pixel;
303
304 info->buffer_length = fixinfo.smem_len;
305 info->line_length = fixinfo.line_length;
Derek Foreman61793382015-09-02 13:45:20 -0500306 strncpy(info->id, fixinfo.id, sizeof(info->id));
Bryce Harrington44bbdd02015-09-23 17:39:05 -0700307 info->id[sizeof(info->id)-1] = '\0';
Philip Withnall4f499172013-02-02 12:02:32 +0000308
309 info->pixel_format = calculate_pixman_format(&varinfo, &fixinfo);
310 info->refresh_rate = calculate_refresh_rate(&varinfo);
311
312 if (info->pixel_format == 0) {
313 weston_log("Frame buffer uses an unsupported format.\n");
314 return -1;
315 }
316
317 return 1;
318}
319
320static int
321fbdev_set_screen_info(struct fbdev_output *output, int fd,
322 struct fbdev_screeninfo *info)
323{
324 struct fb_var_screeninfo varinfo;
325
326 /* Grab the current screen information. */
327 if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
328 return -1;
329 }
330
331 /* Update the information. */
332 varinfo.xres = info->x_resolution;
333 varinfo.yres = info->y_resolution;
334 varinfo.width = info->width_mm;
335 varinfo.height = info->height_mm;
336 varinfo.bits_per_pixel = info->bits_per_pixel;
337
338 /* Try to set up an ARGB (x8r8g8b8) pixel format. */
339 varinfo.grayscale = 0;
340 varinfo.transp.offset = 24;
341 varinfo.transp.length = 0;
342 varinfo.transp.msb_right = 0;
343 varinfo.red.offset = 16;
344 varinfo.red.length = 8;
345 varinfo.red.msb_right = 0;
346 varinfo.green.offset = 8;
347 varinfo.green.length = 8;
348 varinfo.green.msb_right = 0;
349 varinfo.blue.offset = 0;
350 varinfo.blue.length = 8;
351 varinfo.blue.msb_right = 0;
352
353 /* Set the device's screen information. */
354 if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
355 return -1;
356 }
357
358 return 1;
359}
360
361static void fbdev_frame_buffer_destroy(struct fbdev_output *output);
362
363/* Returns an FD for the frame buffer device. */
364static int
365fbdev_frame_buffer_open(struct fbdev_output *output, const char *fb_dev,
366 struct fbdev_screeninfo *screen_info)
367{
368 int fd = -1;
369
370 weston_log("Opening fbdev frame buffer.\n");
371
372 /* Open the frame buffer device. */
373 fd = open(fb_dev, O_RDWR | O_CLOEXEC);
374 if (fd < 0) {
375 weston_log("Failed to open frame buffer device ‘%s’: %s\n",
376 fb_dev, strerror(errno));
377 return -1;
378 }
379
380 /* Grab the screen info. */
381 if (fbdev_query_screen_info(output, fd, screen_info) < 0) {
382 weston_log("Failed to get frame buffer info: %s\n",
383 strerror(errno));
384
385 close(fd);
386 return -1;
387 }
388
389 return fd;
390}
391
392/* Closes the FD on success or failure. */
393static int
394fbdev_frame_buffer_map(struct fbdev_output *output, int fd)
395{
396 int retval = -1;
397
398 weston_log("Mapping fbdev frame buffer.\n");
399
400 /* Map the frame buffer. Write-only mode, since we don't want to read
401 * anything back (because it's slow). */
402 output->fb = mmap(NULL, output->fb_info.buffer_length,
403 PROT_WRITE, MAP_SHARED, fd, 0);
404 if (output->fb == MAP_FAILED) {
405 weston_log("Failed to mmap frame buffer: %s\n",
406 strerror(errno));
407 goto out_close;
408 }
409
410 /* Create a pixman image to wrap the memory mapped frame buffer. */
411 output->hw_surface =
412 pixman_image_create_bits(output->fb_info.pixel_format,
413 output->fb_info.x_resolution,
414 output->fb_info.y_resolution,
415 output->fb,
416 output->fb_info.line_length);
417 if (output->hw_surface == NULL) {
418 weston_log("Failed to create surface for frame buffer.\n");
419 goto out_unmap;
420 }
421
422 /* Success! */
423 retval = 0;
424
425out_unmap:
426 if (retval != 0 && output->fb != NULL)
427 fbdev_frame_buffer_destroy(output);
428
429out_close:
430 if (fd >= 0)
431 close(fd);
432
433 return retval;
434}
435
436static void
437fbdev_frame_buffer_destroy(struct fbdev_output *output)
438{
439 weston_log("Destroying fbdev frame buffer.\n");
440
441 if (munmap(output->fb, output->fb_info.buffer_length) < 0)
442 weston_log("Failed to munmap frame buffer: %s\n",
443 strerror(errno));
444
445 output->fb = NULL;
446}
447
448static void fbdev_output_destroy(struct weston_output *base);
449static void fbdev_output_disable(struct weston_output *base);
450
451static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300452fbdev_output_create(struct fbdev_backend *backend,
Philip Withnall4f499172013-02-02 12:02:32 +0000453 const char *device)
454{
455 struct fbdev_output *output;
Philip Withnall4f499172013-02-02 12:02:32 +0000456 int fb_fd;
Philip Withnall4f499172013-02-02 12:02:32 +0000457 struct wl_event_loop *loop;
458
459 weston_log("Creating fbdev output.\n");
460
Bryce Harringtonde16d892014-11-20 22:21:57 -0800461 output = zalloc(sizeof *output);
462 if (output == NULL)
Philip Withnall4f499172013-02-02 12:02:32 +0000463 return -1;
464
Giulio Camuffo954f1832014-10-11 18:27:30 +0300465 output->backend = backend;
Pekka Paalanene5b56592016-04-28 15:12:25 +0300466 output->device = strdup(device);
Philip Withnall4f499172013-02-02 12:02:32 +0000467
468 /* Create the frame buffer. */
469 fb_fd = fbdev_frame_buffer_open(output, device, &output->fb_info);
470 if (fb_fd < 0) {
471 weston_log("Creating frame buffer failed.\n");
472 goto out_free;
473 }
Giulio Camuffo954f1832014-10-11 18:27:30 +0300474 if (backend->use_pixman) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300475 if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
476 weston_log("Mapping frame buffer failed.\n");
477 goto out_free;
478 }
Kristian Høgsberg8ac6a2d2013-10-09 09:59:06 -0700479 } else {
480 close(fb_fd);
Philip Withnall4f499172013-02-02 12:02:32 +0000481 }
482
Jonas Ådahle5a12252013-04-05 23:07:11 +0200483 output->base.start_repaint_loop = fbdev_output_start_repaint_loop;
Philip Withnall4f499172013-02-02 12:02:32 +0000484 output->base.repaint = fbdev_output_repaint;
485 output->base.destroy = fbdev_output_destroy;
Philip Withnall4f499172013-02-02 12:02:32 +0000486
487 /* only one static mode in list */
488 output->mode.flags =
489 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
490 output->mode.width = output->fb_info.x_resolution;
491 output->mode.height = output->fb_info.y_resolution;
492 output->mode.refresh = output->fb_info.refresh_rate;
493 wl_list_init(&output->base.mode_list);
494 wl_list_insert(&output->base.mode_list, &output->mode.link);
495
Hardeningff39efa2013-09-18 23:56:35 +0200496 output->base.current_mode = &output->mode;
Philip Withnall4f499172013-02-02 12:02:32 +0000497 output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
498 output->base.make = "unknown";
499 output->base.model = output->fb_info.id;
Derek Foremane516c3b2015-03-17 13:22:34 -0500500 output->base.name = strdup("fbdev");
Philip Withnall4f499172013-02-02 12:02:32 +0000501
Giulio Camuffo954f1832014-10-11 18:27:30 +0300502 weston_output_init(&output->base, backend->compositor,
Philip Withnall4f499172013-02-02 12:02:32 +0000503 0, 0, output->fb_info.width_mm,
504 output->fb_info.height_mm,
Benoit Gschwind934e89a2016-04-27 23:56:42 +0200505 backend->output_transform,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200506 1);
Philip Withnall4f499172013-02-02 12:02:32 +0000507
Giulio Camuffo954f1832014-10-11 18:27:30 +0300508 if (backend->use_pixman) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300509 if (pixman_renderer_output_create(&output->base) < 0)
Sjoerd Simonsc112e0c2015-12-04 19:20:12 -0600510 goto out_hw_surface;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300511 } else {
512 setenv("HYBRIS_EGLPLATFORM", "wayland", 1);
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300513 if (gl_renderer->output_create(&output->base,
Jonny Lamb671148f2015-03-20 15:26:52 +0100514 (EGLNativeWindowType)NULL, NULL,
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000515 gl_renderer->opaque_attribs,
Derek Foremane76f1852015-05-15 12:12:39 -0500516 NULL, 0) < 0) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300517 weston_log("gl_renderer_output_create failed.\n");
Sjoerd Simonsc112e0c2015-12-04 19:20:12 -0600518 goto out_hw_surface;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300519 }
520 }
521
Giulio Camuffo954f1832014-10-11 18:27:30 +0300522 loop = wl_display_get_event_loop(backend->compositor->wl_display);
Philip Withnall4f499172013-02-02 12:02:32 +0000523 output->finish_frame_timer =
524 wl_event_loop_add_timer(loop, finish_frame_handler, output);
525
Giulio Camuffo954f1832014-10-11 18:27:30 +0300526 weston_compositor_add_output(backend->compositor, &output->base);
Philip Withnall4f499172013-02-02 12:02:32 +0000527
528 weston_log("fbdev output %d×%d px\n",
529 output->mode.width, output->mode.height);
530 weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
531 output->mode.refresh / 1000);
532
533 return 0;
534
Philip Withnall4f499172013-02-02 12:02:32 +0000535out_hw_surface:
Philip Withnall4f499172013-02-02 12:02:32 +0000536 pixman_image_unref(output->hw_surface);
537 output->hw_surface = NULL;
538 weston_output_destroy(&output->base);
539 fbdev_frame_buffer_destroy(output);
540out_free:
Pekka Paalanene5b56592016-04-28 15:12:25 +0300541 free(output->device);
Philip Withnall4f499172013-02-02 12:02:32 +0000542 free(output);
543
544 return -1;
545}
546
547static void
548fbdev_output_destroy(struct weston_output *base)
549{
550 struct fbdev_output *output = to_fbdev_output(base);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300551 struct fbdev_backend *backend = output->backend;
Philip Withnall4f499172013-02-02 12:02:32 +0000552
553 weston_log("Destroying fbdev output.\n");
554
555 /* Close the frame buffer. */
556 fbdev_output_disable(base);
557
Giulio Camuffo954f1832014-10-11 18:27:30 +0300558 if (backend->use_pixman) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300559 if (base->renderer_state != NULL)
560 pixman_renderer_output_destroy(base);
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300561 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300562 gl_renderer->output_destroy(base);
Philip Withnall4f499172013-02-02 12:02:32 +0000563 }
564
565 /* Remove the output. */
Philip Withnall4f499172013-02-02 12:02:32 +0000566 weston_output_destroy(&output->base);
567
Pekka Paalanene5b56592016-04-28 15:12:25 +0300568 free(output->device);
Philip Withnall4f499172013-02-02 12:02:32 +0000569 free(output);
570}
571
572/* strcmp()-style return values. */
573static int
574compare_screen_info (const struct fbdev_screeninfo *a,
575 const struct fbdev_screeninfo *b)
576{
577 if (a->x_resolution == b->x_resolution &&
578 a->y_resolution == b->y_resolution &&
579 a->width_mm == b->width_mm &&
580 a->height_mm == b->height_mm &&
581 a->bits_per_pixel == b->bits_per_pixel &&
582 a->pixel_format == b->pixel_format &&
583 a->refresh_rate == b->refresh_rate)
584 return 0;
585
586 return 1;
587}
588
589static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300590fbdev_output_reenable(struct fbdev_backend *backend,
Philip Withnall4f499172013-02-02 12:02:32 +0000591 struct weston_output *base)
592{
593 struct fbdev_output *output = to_fbdev_output(base);
594 struct fbdev_screeninfo new_screen_info;
595 int fb_fd;
Pekka Paalanene5b56592016-04-28 15:12:25 +0300596 char *device;
Philip Withnall4f499172013-02-02 12:02:32 +0000597
598 weston_log("Re-enabling fbdev output.\n");
599
600 /* Create the frame buffer. */
601 fb_fd = fbdev_frame_buffer_open(output, output->device,
602 &new_screen_info);
603 if (fb_fd < 0) {
604 weston_log("Creating frame buffer failed.\n");
605 goto err;
606 }
607
608 /* Check whether the frame buffer details have changed since we were
609 * disabled. */
610 if (compare_screen_info (&output->fb_info, &new_screen_info) != 0) {
611 /* Perform a mode-set to restore the old mode. */
612 if (fbdev_set_screen_info(output, fb_fd,
613 &output->fb_info) < 0) {
614 weston_log("Failed to restore mode settings. "
615 "Attempting to re-open output anyway.\n");
616 }
617
Rob Bradford581b3fd2013-07-26 16:29:39 +0100618 close(fb_fd);
619
Philip Withnall4f499172013-02-02 12:02:32 +0000620 /* Remove and re-add the output so that resources depending on
621 * the frame buffer X/Y resolution (such as the shadow buffer)
622 * are re-initialised. */
Pekka Paalanene5b56592016-04-28 15:12:25 +0300623 device = strdup(output->device);
624 fbdev_output_destroy(&output->base);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300625 fbdev_output_create(backend, device);
Pekka Paalanene5b56592016-04-28 15:12:25 +0300626 free(device);
Philip Withnall4f499172013-02-02 12:02:32 +0000627
628 return 0;
629 }
630
631 /* Map the device if it has the same details as before. */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300632 if (backend->use_pixman) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300633 if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
634 weston_log("Mapping frame buffer failed.\n");
635 goto err;
636 }
Philip Withnall4f499172013-02-02 12:02:32 +0000637 }
638
639 return 0;
640
641err:
642 return -1;
643}
644
645/* NOTE: This leaves output->fb_info populated, caching data so that if
646 * fbdev_output_reenable() is called again, it can determine whether a mode-set
647 * is needed. */
648static void
649fbdev_output_disable(struct weston_output *base)
650{
651 struct fbdev_output *output = to_fbdev_output(base);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300652 struct fbdev_backend *backend = output->backend;
Philip Withnall4f499172013-02-02 12:02:32 +0000653
654 weston_log("Disabling fbdev output.\n");
655
Giulio Camuffo954f1832014-10-11 18:27:30 +0300656 if ( ! backend->use_pixman) return;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300657
Philip Withnall4f499172013-02-02 12:02:32 +0000658 if (output->hw_surface != NULL) {
659 pixman_image_unref(output->hw_surface);
660 output->hw_surface = NULL;
661 }
662
663 fbdev_frame_buffer_destroy(output);
664}
665
666static void
Giulio Camuffo954f1832014-10-11 18:27:30 +0300667fbdev_backend_destroy(struct weston_compositor *base)
Philip Withnall4f499172013-02-02 12:02:32 +0000668{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300669 struct fbdev_backend *backend = to_fbdev_backend(base);
Philip Withnall4f499172013-02-02 12:02:32 +0000670
Giulio Camuffo954f1832014-10-11 18:27:30 +0300671 udev_input_destroy(&backend->input);
Philip Withnall4f499172013-02-02 12:02:32 +0000672
673 /* Destroy the output. */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300674 weston_compositor_shutdown(base);
Philip Withnall4f499172013-02-02 12:02:32 +0000675
676 /* Chain up. */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300677 weston_launcher_destroy(base->launcher);
Philip Withnall4f499172013-02-02 12:02:32 +0000678
Giulio Camuffo954f1832014-10-11 18:27:30 +0300679 free(backend);
Philip Withnall4f499172013-02-02 12:02:32 +0000680}
681
682static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700683session_notify(struct wl_listener *listener, void *data)
Philip Withnall4f499172013-02-02 12:02:32 +0000684{
Pekka Paalanen3f897942015-08-19 13:52:47 +0300685 struct weston_compositor *compositor = data;
686 struct fbdev_backend *backend = to_fbdev_backend(compositor);
Philip Withnall4f499172013-02-02 12:02:32 +0000687 struct weston_output *output;
688
Giulio Camuffo954f1832014-10-11 18:27:30 +0300689 if (compositor->session_active) {
Philip Withnall4f499172013-02-02 12:02:32 +0000690 weston_log("entering VT\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +0300691 compositor->state = backend->prev_state;
Philip Withnall4f499172013-02-02 12:02:32 +0000692
Giulio Camuffo954f1832014-10-11 18:27:30 +0300693 wl_list_for_each(output, &compositor->output_list, link) {
694 fbdev_output_reenable(backend, output);
Philip Withnall4f499172013-02-02 12:02:32 +0000695 }
696
Giulio Camuffo954f1832014-10-11 18:27:30 +0300697 weston_compositor_damage_all(compositor);
Philip Withnall4f499172013-02-02 12:02:32 +0000698
Giulio Camuffo954f1832014-10-11 18:27:30 +0300699 udev_input_enable(&backend->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700700 } else {
Philip Withnall4f499172013-02-02 12:02:32 +0000701 weston_log("leaving VT\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +0300702 udev_input_disable(&backend->input);
Philip Withnall4f499172013-02-02 12:02:32 +0000703
Giulio Camuffo954f1832014-10-11 18:27:30 +0300704 wl_list_for_each(output, &compositor->output_list, link) {
Philip Withnall4f499172013-02-02 12:02:32 +0000705 fbdev_output_disable(output);
706 }
707
Giulio Camuffo954f1832014-10-11 18:27:30 +0300708 backend->prev_state = compositor->state;
709 weston_compositor_offscreen(compositor);
Philip Withnall4f499172013-02-02 12:02:32 +0000710
711 /* If we have a repaint scheduled (from the idle handler), make
712 * sure we cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +0100713 * vt switched away. The OFFSCREEN state will prevent
Bryce Harringtonc2be8572015-12-11 13:11:37 -0800714 * further attempts at repainting. When we switch
Philip Withnall4f499172013-02-02 12:02:32 +0000715 * back, we schedule a repaint, which will process
716 * pending frame callbacks. */
717
718 wl_list_for_each(output,
Giulio Camuffo954f1832014-10-11 18:27:30 +0300719 &compositor->output_list, link) {
Philip Withnall4f499172013-02-02 12:02:32 +0000720 output->repaint_needed = 0;
721 }
nerdopolis38946702014-12-03 15:53:03 +0000722 }
Philip Withnall4f499172013-02-02 12:02:32 +0000723}
724
725static void
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700726fbdev_restore(struct weston_compositor *compositor)
Philip Withnall4f499172013-02-02 12:02:32 +0000727{
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700728 weston_launcher_restore(compositor->launcher);
Philip Withnall4f499172013-02-02 12:02:32 +0000729}
730
Giulio Camuffo954f1832014-10-11 18:27:30 +0300731static struct fbdev_backend *
732fbdev_backend_create(struct weston_compositor *compositor, int *argc, char *argv[],
733 struct weston_config *config,
Benoit Gschwind934e89a2016-04-27 23:56:42 +0200734 struct weston_fbdev_backend_config *param)
Philip Withnall4f499172013-02-02 12:02:32 +0000735{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300736 struct fbdev_backend *backend;
Rob Bradford2387fde2013-05-31 18:09:57 +0100737 const char *seat_id = default_seat;
Philip Withnall4f499172013-02-02 12:02:32 +0000738
739 weston_log("initializing fbdev backend\n");
740
Giulio Camuffo954f1832014-10-11 18:27:30 +0300741 backend = zalloc(sizeof *backend);
742 if (backend == NULL)
Philip Withnall4f499172013-02-02 12:02:32 +0000743 return NULL;
744
Giulio Camuffo954f1832014-10-11 18:27:30 +0300745 backend->compositor = compositor;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400746 if (weston_compositor_set_presentation_clock_software(
Giulio Camuffo954f1832014-10-11 18:27:30 +0300747 compositor) < 0)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400748 goto out_compositor;
749
Giulio Camuffo954f1832014-10-11 18:27:30 +0300750 backend->udev = udev_new();
751 if (backend->udev == NULL) {
Philip Withnall4f499172013-02-02 12:02:32 +0000752 weston_log("Failed to initialize udev context.\n");
753 goto out_compositor;
754 }
755
756 /* Set up the TTY. */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300757 backend->session_listener.notify = session_notify;
758 wl_signal_add(&compositor->session_signal,
759 &backend->session_listener);
760 compositor->launcher =
761 weston_launcher_connect(compositor, param->tty, "seat0", false);
762 if (!compositor->launcher) {
David Herrmann1641d142013-10-15 14:29:57 +0200763 weston_log("fatal: fbdev backend should be run "
764 "using weston-launch binary or as root\n");
Philip Withnall4f499172013-02-02 12:02:32 +0000765 goto out_udev;
766 }
767
Giulio Camuffo954f1832014-10-11 18:27:30 +0300768 backend->base.destroy = fbdev_backend_destroy;
769 backend->base.restore = fbdev_restore;
Philip Withnall4f499172013-02-02 12:02:32 +0000770
Giulio Camuffo954f1832014-10-11 18:27:30 +0300771 backend->prev_state = WESTON_COMPOSITOR_ACTIVE;
772 backend->use_pixman = !param->use_gl;
Benoit Gschwind934e89a2016-04-27 23:56:42 +0200773 backend->output_transform = param->output_transform;
Philip Withnall4f499172013-02-02 12:02:32 +0000774
Bob Ham91880f12016-01-12 10:21:47 +0000775 weston_setup_vt_switch_bindings(compositor);
776
Giulio Camuffo954f1832014-10-11 18:27:30 +0300777 if (backend->use_pixman) {
778 if (pixman_renderer_init(compositor) < 0)
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700779 goto out_launcher;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300780 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300781 gl_renderer = weston_load_module("gl-renderer.so",
782 "gl_renderer_interface");
783 if (!gl_renderer) {
784 weston_log("could not load gl renderer\n");
785 goto out_launcher;
786 }
787
Giulio Camuffo954f1832014-10-11 18:27:30 +0300788 if (gl_renderer->create(compositor, NO_EGL_PLATFORM,
Jonny Lamb74eed312015-03-24 13:12:04 +0100789 EGL_DEFAULT_DISPLAY,
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300790 gl_renderer->opaque_attribs,
Derek Foremane76f1852015-05-15 12:12:39 -0500791 NULL, 0) < 0) {
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300792 weston_log("gl_renderer_create failed.\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700793 goto out_launcher;
Adrian Negreanu4aa756d2013-09-06 15:16:09 +0300794 }
795 }
Philip Withnall4f499172013-02-02 12:02:32 +0000796
Giulio Camuffo954f1832014-10-11 18:27:30 +0300797 if (fbdev_output_create(backend, param->device) < 0)
Dawid Gajownik82d49252015-07-31 00:02:28 -0300798 goto out_launcher;
Philip Withnall4f499172013-02-02 12:02:32 +0000799
Giulio Camuffo954f1832014-10-11 18:27:30 +0300800 udev_input_init(&backend->input, compositor, backend->udev, seat_id);
Philip Withnall4f499172013-02-02 12:02:32 +0000801
Giulio Camuffo954f1832014-10-11 18:27:30 +0300802 compositor->backend = &backend->base;
803 return backend;
Philip Withnall4f499172013-02-02 12:02:32 +0000804
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700805out_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300806 weston_launcher_destroy(compositor->launcher);
Philip Withnall4f499172013-02-02 12:02:32 +0000807
808out_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300809 udev_unref(backend->udev);
Philip Withnall4f499172013-02-02 12:02:32 +0000810
811out_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300812 weston_compositor_shutdown(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300813 free(backend);
Philip Withnall4f499172013-02-02 12:02:32 +0000814
815 return NULL;
816}
817
Benoit Gschwind934e89a2016-04-27 23:56:42 +0200818static void
819config_init_to_defaults(struct weston_fbdev_backend_config *config)
820{
821 /* TODO: Ideally, available frame buffers should be enumerated using
822 * udev, rather than passing a device node in as a parameter. */
823 config->tty = 0; /* default to current tty */
824 config->device = "/dev/fb0"; /* default frame buffer */
825 config->use_gl = 0;
826 config->output_transform = WL_OUTPUT_TRANSFORM_NORMAL;
827}
828
Giulio Camuffo954f1832014-10-11 18:27:30 +0300829WL_EXPORT int
830backend_init(struct weston_compositor *compositor, int *argc, char *argv[],
Benoit Gschwind934e89a2016-04-27 23:56:42 +0200831 struct weston_config *wc,
Giulio Camuffo93daabb2015-10-17 19:24:14 +0300832 struct weston_backend_config *config_base)
Philip Withnall4f499172013-02-02 12:02:32 +0000833{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300834 struct fbdev_backend *b;
Benoit Gschwind934e89a2016-04-27 23:56:42 +0200835 struct weston_fbdev_backend_config config = {{ 0, }};
Philip Withnall4f499172013-02-02 12:02:32 +0000836
Benoit Gschwind934e89a2016-04-27 23:56:42 +0200837 if (config_base == NULL ||
838 config_base->struct_version != WESTON_FBDEV_BACKEND_CONFIG_VERSION ||
839 config_base->struct_size > sizeof(struct weston_fbdev_backend_config)) {
840 weston_log("fbdev backend config structure is invalid\n");
841 return -1;
842 }
Philip Withnall4f499172013-02-02 12:02:32 +0000843
Benoit Gschwind934e89a2016-04-27 23:56:42 +0200844 config_init_to_defaults(&config);
845 memcpy(&config, config_base, config_base->struct_size);
Philip Withnall4f499172013-02-02 12:02:32 +0000846
Benoit Gschwind934e89a2016-04-27 23:56:42 +0200847 b = fbdev_backend_create(compositor, argc, argv, wc, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300848 if (b == NULL)
849 return -1;
850 return 0;
Philip Withnall4f499172013-02-02 12:02:32 +0000851}