2 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
4 * Copyright © 2012-2013 Raspberry Pi Foundation
6 * Permission to use, copy, modify, distribute, and sell this software and
7 * its documentation for any purpose is hereby granted without fee, provided
8 * that the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of the copyright holders not be used in
11 * advertising or publicity pertaining to distribution of the software
12 * without specific, written prior permission. The copyright holders make
13 * no representations about the suitability of this software for any
14 * purpose. It is provided "as is" without express or implied warranty.
16 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
20 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
21 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33 #include <sys/types.h>
37 #include <linux/input.h>
41 # include <bcm_host.h>
43 # include "rpi-bcm-stubs.h"
46 #include "compositor.h"
47 #include "rpi-renderer.h"
48 #include "launcher-util.h"
49 #include "udev-input.h"
53 weston_log(__VA_ARGS__)
55 #define DBG(...) do {} while (0)
58 struct rpi_compositor;
64 struct wl_event_source *source;
68 struct rpi_compositor *compositor;
69 struct weston_output base;
72 struct weston_mode mode;
73 struct rpi_flippipe flippipe;
75 DISPMANX_DISPLAY_HANDLE_T display;
79 struct weston_seat base;
80 struct wl_list devices_list;
82 struct udev_monitor *udev_monitor;
83 struct wl_event_source *udev_monitor_source;
87 struct rpi_compositor {
88 struct weston_compositor base;
92 struct udev_input input;
93 struct wl_listener session_listener;
98 static inline struct rpi_output *
99 to_rpi_output(struct weston_output *base)
101 return container_of(base, struct rpi_output, base);
104 static inline struct rpi_seat *
105 to_rpi_seat(struct weston_seat *base)
107 return container_of(base, struct rpi_seat, base);
110 static inline struct rpi_compositor *
111 to_rpi_compositor(struct weston_compositor *base)
113 return container_of(base, struct rpi_compositor, base);
117 rpi_get_current_time(void)
121 /* XXX: use CLOCK_MONOTONIC instead? */
122 gettimeofday(&tv, NULL);
123 return (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
127 rpi_flippipe_update_complete(DISPMANX_UPDATE_HANDLE_T update, void *data)
129 /* This function runs in a different thread. */
130 struct rpi_flippipe *flippipe = data;
134 /* manufacture flip completion timestamp */
135 time = rpi_get_current_time();
137 ret = write(flippipe->writefd, &time, sizeof time);
138 if (ret != sizeof time)
139 weston_log("ERROR: %s failed to write, ret %zd, errno %d\n",
140 __func__, ret, errno);
144 rpi_dispmanx_update_submit(DISPMANX_UPDATE_HANDLE_T update,
145 struct rpi_output *output)
148 * The callback registered here will eventually be called
149 * in a different thread context. Therefore we cannot call
150 * the usual functions from rpi_flippipe_update_complete().
151 * Instead, we have a pipe for passing the message from the
152 * thread, waking up the Weston main event loop, calling
153 * rpi_flippipe_handler(), and then ending up in
154 * rpi_output_update_complete() in the main thread context,
155 * where we can do the frame finishing work.
157 return vc_dispmanx_update_submit(update, rpi_flippipe_update_complete,
162 rpi_output_update_complete(struct rpi_output *output, uint64_t time);
165 rpi_flippipe_handler(int fd, uint32_t mask, void *data)
167 struct rpi_output *output = data;
171 if (mask != WL_EVENT_READABLE)
172 weston_log("ERROR: unexpected mask 0x%x in %s\n",
175 ret = read(fd, &time, sizeof time);
176 if (ret != sizeof time) {
177 weston_log("ERROR: %s failed to read, ret %zd, errno %d\n",
178 __func__, ret, errno);
181 rpi_output_update_complete(output, time);
187 rpi_flippipe_init(struct rpi_flippipe *flippipe, struct rpi_output *output)
189 struct wl_event_loop *loop;
192 if (pipe2(fd, O_CLOEXEC) == -1)
195 flippipe->readfd = fd[0];
196 flippipe->writefd = fd[1];
198 loop = wl_display_get_event_loop(output->compositor->base.wl_display);
199 flippipe->source = wl_event_loop_add_fd(loop, flippipe->readfd,
201 rpi_flippipe_handler, output);
203 if (!flippipe->source) {
204 close(flippipe->readfd);
205 close(flippipe->writefd);
213 rpi_flippipe_release(struct rpi_flippipe *flippipe)
215 wl_event_source_remove(flippipe->source);
216 close(flippipe->readfd);
217 close(flippipe->writefd);
221 rpi_output_start_repaint_loop(struct weston_output *output)
225 time = rpi_get_current_time();
226 weston_output_finish_frame(output, time);
230 rpi_output_repaint(struct weston_output *base, pixman_region32_t *damage)
232 struct rpi_output *output = to_rpi_output(base);
233 struct rpi_compositor *compositor = output->compositor;
234 struct weston_plane *primary_plane = &compositor->base.primary_plane;
235 DISPMANX_UPDATE_HANDLE_T update;
237 DBG("frame update start\n");
239 /* Update priority higher than in rpi-renderer's
240 * output destroy function, see rpi_output_destroy().
242 update = vc_dispmanx_update_start(1);
244 rpi_renderer_set_update_handle(&output->base, update);
245 compositor->base.renderer->repaint_output(&output->base, damage);
247 pixman_region32_subtract(&primary_plane->damage,
248 &primary_plane->damage, damage);
250 /* schedule callback to rpi_output_update_complete() */
251 rpi_dispmanx_update_submit(update, output);
252 DBG("frame update submitted\n");
257 rpi_output_update_complete(struct rpi_output *output, uint64_t time)
259 DBG("frame update complete(%" PRIu64 ")\n", time);
260 rpi_renderer_finish_frame(&output->base);
261 weston_output_finish_frame(&output->base, time);
265 rpi_output_destroy(struct weston_output *base)
267 struct rpi_output *output = to_rpi_output(base);
269 DBG("%s\n", __func__);
271 rpi_renderer_output_destroy(base);
273 /* rpi_renderer_output_destroy() will schedule a removal of
274 * all Dispmanx Elements, and wait for the update to complete.
275 * Assuming updates are sequential, the wait should guarantee,
276 * that any pending rpi_flippipe_update_complete() callbacks
277 * have happened already. Therefore we can destroy the flippipe
280 rpi_flippipe_release(&output->flippipe);
282 weston_output_destroy(&output->base);
284 vc_dispmanx_display_close(output->display);
289 static const char *transform_names[] = {
290 [WL_OUTPUT_TRANSFORM_NORMAL] = "normal",
291 [WL_OUTPUT_TRANSFORM_90] = "90",
292 [WL_OUTPUT_TRANSFORM_180] = "180",
293 [WL_OUTPUT_TRANSFORM_270] = "270",
294 [WL_OUTPUT_TRANSFORM_FLIPPED] = "flipped",
295 [WL_OUTPUT_TRANSFORM_FLIPPED_90] = "flipped-90",
296 [WL_OUTPUT_TRANSFORM_FLIPPED_180] = "flipped-180",
297 [WL_OUTPUT_TRANSFORM_FLIPPED_270] = "flipped-270",
301 str2transform(const char *name)
305 for (i = 0; i < ARRAY_LENGTH(transform_names); i++)
306 if (strcmp(name, transform_names[i]) == 0)
313 transform2str(uint32_t output_transform)
315 if (output_transform >= ARRAY_LENGTH(transform_names))
316 return "<illegal value>";
318 return transform_names[output_transform];
322 rpi_output_create(struct rpi_compositor *compositor, uint32_t transform)
324 struct rpi_output *output;
325 DISPMANX_MODEINFO_T modeinfo;
327 float mm_width, mm_height;
329 output = calloc(1, sizeof *output);
333 output->compositor = compositor;
334 output->single_buffer = compositor->single_buffer;
336 if (rpi_flippipe_init(&output->flippipe, output) < 0) {
337 weston_log("Creating message pipe failed.\n");
341 output->display = vc_dispmanx_display_open(DISPMANX_ID_HDMI);
342 if (!output->display) {
343 weston_log("Failed to open dispmanx HDMI display.\n");
347 ret = vc_dispmanx_display_get_info(output->display, &modeinfo);
349 weston_log("Failed to get display mode information.\n");
353 output->base.start_repaint_loop = rpi_output_start_repaint_loop;
354 output->base.repaint = rpi_output_repaint;
355 output->base.destroy = rpi_output_destroy;
356 output->base.assign_planes = NULL;
357 output->base.set_backlight = NULL;
358 output->base.set_dpms = NULL;
359 output->base.switch_mode = NULL;
361 /* XXX: use tvservice to get information from and control the
362 * HDMI and SDTV outputs. See:
363 * /opt/vc/include/interface/vmcs_host/vc_tvservice.h
366 /* only one static mode in list */
368 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
369 output->mode.width = modeinfo.width;
370 output->mode.height = modeinfo.height;
371 output->mode.refresh = 60000;
372 wl_list_init(&output->base.mode_list);
373 wl_list_insert(&output->base.mode_list, &output->mode.link);
375 output->base.current_mode = &output->mode;
376 output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
377 output->base.make = "unknown";
378 output->base.model = "unknown";
381 mm_width = modeinfo.width * (25.4f / 96.0f);
382 mm_height = modeinfo.height * (25.4f / 96.0f);
384 weston_output_init(&output->base, &compositor->base,
385 0, 0, round(mm_width), round(mm_height),
388 if (rpi_renderer_output_create(&output->base, output->display) < 0)
391 wl_list_insert(compositor->base.output_list.prev, &output->base.link);
393 weston_log("Raspberry Pi HDMI output %dx%d px\n",
394 output->mode.width, output->mode.height);
395 weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
396 output->mode.refresh / 1000);
397 weston_log_continue(STAMP_SPACE "orientation: %s\n",
398 transform2str(output->base.transform));
400 if (!strncmp(transform2str(output->base.transform), "flipped", 7))
401 weston_log("warning: flipped output transforms may not work\n");
406 weston_output_destroy(&output->base);
409 vc_dispmanx_display_close(output->display);
412 rpi_flippipe_release(&output->flippipe);
420 rpi_compositor_destroy(struct weston_compositor *base)
422 struct rpi_compositor *compositor = to_rpi_compositor(base);
424 udev_input_destroy(&compositor->input);
426 /* destroys outputs, too */
427 weston_compositor_shutdown(&compositor->base);
429 weston_launcher_destroy(compositor->base.launcher);
436 session_notify(struct wl_listener *listener, void *data)
438 struct rpi_compositor *compositor = data;
439 struct weston_output *output;
441 if (compositor->base.session_active) {
442 weston_log("activating session\n");
443 compositor->base.state = compositor->prev_state;
444 weston_compositor_damage_all(&compositor->base);
445 udev_input_enable(&compositor->input);
447 weston_log("deactivating session\n");
448 udev_input_disable(&compositor->input);
450 compositor->prev_state = compositor->base.state;
451 weston_compositor_offscreen(&compositor->base);
453 /* If we have a repaint scheduled (either from a
454 * pending pageflip or the idle handler), make sure we
455 * cancel that so we don't try to pageflip when we're
456 * vt switched away. The OFFSCREEN state will prevent
457 * further attemps at repainting. When we switch
458 * back, we schedule a repaint, which will process
459 * pending frame callbacks. */
461 wl_list_for_each(output,
462 &compositor->base.output_list, link) {
463 output->repaint_needed = 0;
469 rpi_restore(struct weston_compositor *compositor)
471 weston_launcher_restore(compositor->launcher);
475 switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
477 struct weston_compositor *compositor = data;
479 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
482 struct rpi_parameters {
484 struct rpi_renderer_parameters renderer;
485 uint32_t output_transform;
488 static struct weston_compositor *
489 rpi_compositor_create(struct wl_display *display, int *argc, char *argv[],
490 struct weston_config *config,
491 struct rpi_parameters *param)
493 struct rpi_compositor *compositor;
496 weston_log("initializing Raspberry Pi backend\n");
498 compositor = calloc(1, sizeof *compositor);
499 if (compositor == NULL)
502 if (weston_compositor_init(&compositor->base, display, argc, argv,
506 compositor->udev = udev_new();
507 if (compositor->udev == NULL) {
508 weston_log("Failed to initialize udev context.\n");
512 compositor->session_listener.notify = session_notify;
513 wl_signal_add(&compositor->base.session_signal,
514 &compositor ->session_listener);
515 compositor->base.launcher =
516 weston_launcher_connect(&compositor->base, param->tty, "seat0");
517 if (!compositor->base.launcher) {
518 weston_log("Failed to initialize tty.\n");
522 compositor->base.destroy = rpi_compositor_destroy;
523 compositor->base.restore = rpi_restore;
525 compositor->prev_state = WESTON_COMPOSITOR_ACTIVE;
526 compositor->single_buffer = param->renderer.single_buffer;
528 weston_log("Dispmanx planes are %s buffered.\n",
529 compositor->single_buffer ? "single" : "double");
531 for (key = KEY_F1; key < KEY_F9; key++)
532 weston_compositor_add_key_binding(&compositor->base, key,
533 MODIFIER_CTRL | MODIFIER_ALT,
534 switch_vt_binding, compositor);
537 * bcm_host_init() creates threads.
538 * Therefore we must have all signal handlers set and signals blocked
539 * before calling it. Otherwise the signals may end in the bcm
540 * threads and cause the default behaviour there. For instance,
541 * SIGUSR1 used for VT switching caused Weston to terminate there.
545 if (rpi_renderer_create(&compositor->base, ¶m->renderer) < 0)
548 if (rpi_output_create(compositor, param->output_transform) < 0)
551 if (udev_input_init(&compositor->input,
553 compositor->udev, "seat0") != 0) {
554 weston_log("Failed to initialize udev input.\n");
558 return &compositor->base;
561 compositor->base.renderer->destroy(&compositor->base);
564 weston_launcher_destroy(compositor->base.launcher);
567 udev_unref(compositor->udev);
570 weston_compositor_shutdown(&compositor->base);
579 WL_EXPORT struct weston_compositor *
580 backend_init(struct wl_display *display, int *argc, char *argv[],
581 struct weston_config *config)
583 const char *transform = "normal";
586 struct rpi_parameters param = {
587 .tty = 0, /* default to current tty */
588 .renderer.single_buffer = 0,
589 .output_transform = WL_OUTPUT_TRANSFORM_NORMAL,
590 .renderer.opaque_regions = 0,
593 const struct weston_option rpi_options[] = {
594 { WESTON_OPTION_INTEGER, "tty", 0, ¶m.tty },
595 { WESTON_OPTION_BOOLEAN, "single-buffer", 0,
596 ¶m.renderer.single_buffer },
597 { WESTON_OPTION_STRING, "transform", 0, &transform },
598 { WESTON_OPTION_BOOLEAN, "opaque-regions", 0,
599 ¶m.renderer.opaque_regions },
602 parse_options(rpi_options, ARRAY_LENGTH(rpi_options), argc, argv);
604 ret = str2transform(transform);
606 weston_log("invalid transform \"%s\"\n", transform);
608 param.output_transform = ret;
610 return rpi_compositor_create(display, argc, argv, config, ¶m);