blob: c75bcda4619e593e0988010e8a031a25d1010465 [file] [log] [blame]
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001/*
2 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
4 * Copyright © 2012 Raspberry Pi Foundation
5 *
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.
15 *
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.
23 */
24
25#define _GNU_SOURCE
26
27#include <errno.h>
28#include <stdlib.h>
29#include <stdio.h>
30#include <string.h>
31#include <math.h>
32#include <sys/types.h>
33#include <fcntl.h>
34#include <unistd.h>
35
36#include <libudev.h>
37
38#include "config.h"
39
40#ifdef HAVE_BCM_HOST
41# include <bcm_host.h>
42#else
43# include "rpi-bcm-stubs.h"
44#endif
45
46#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010047#include "gl-renderer.h"
Pekka Paalanene8de35c2012-11-07 12:25:14 +020048#include "evdev.h"
49
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +020050/*
51 * Dispmanx API offers alpha-blended overlays for hardware compositing.
52 * The final composite consists of dispmanx elements, and their contents:
53 * the dispmanx resource assigned to the element. The elements may be
54 * scanned out directly, or composited to a temporary surface, depending on
55 * how the firmware decides to handle the scene. Updates to multiple elements
56 * may be queued in a single dispmanx update object, resulting in atomic and
57 * vblank synchronized display updates.
58 *
59 * To avoid tearing and display artifacts, the current dispmanx resource in a
60 * dispmanx element must not be touched. Therefore each element must be
61 * double-buffered, using two resources, the front and the back. The update
62 * sequence is:
63 * 0. the front resource is already in-use, the back resource is unused
64 * 1. write data into the back resource
65 * 2. submit an element update, back becomes in-use
66 * 3. swap back and front pointers (both are in-use now)
67 * 4. wait for update_submit completion, the new back resource becomes unused
68 *
69 * A resource may be destroyed only, when the update removing the element has
70 * completed. Otherwise you risk showing an incomplete composition.
71 *
72 * The dispmanx element used as the native window for EGL does not need
73 * manually allocated resources, EGL does double-buffering internally.
74 * Unfortunately it also means, that we cannot alternate between two
75 * buffers like the DRM backend does, since we have no control over what
76 * resources EGL uses. We are forced to use EGL_BUFFER_PRESERVED as the
77 * EGL_SWAP_BEHAVIOR to avoid repainting the whole output every frame.
78 *
79 * We also cannot bundle eglSwapBuffers into our own display update, which
80 * means that Weston's primary plane updates and the overlay updates may
81 * happen unsynchronized.
82 */
83
84#ifndef ELEMENT_CHANGE_LAYER
85/* copied from interface/vmcs_host/vc_vchi_dispmanx.h of userland.git */
86#define ELEMENT_CHANGE_LAYER (1<<0)
87#define ELEMENT_CHANGE_OPACITY (1<<1)
88#define ELEMENT_CHANGE_DEST_RECT (1<<2)
89#define ELEMENT_CHANGE_SRC_RECT (1<<3)
90#define ELEMENT_CHANGE_MASK_RESOURCE (1<<4)
91#define ELEMENT_CHANGE_TRANSFORM (1<<5)
92#endif
93
94/* Enabling this debugging incurs a significant performance hit */
95#if 0
96#define DBG(...) \
97 weston_log(__VA_ARGS__)
98#else
99#define DBG(...) do {} while (0)
100#endif
101
102/* If we had a fully featured vc_dispmanx_resource_write_data()... */
103/*#define HAVE_RESOURCE_WRITE_DATA_RECT 1*/
104
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200105struct rpi_compositor;
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +0200106struct rpi_output;
107
108struct rpi_resource {
109 DISPMANX_RESOURCE_HANDLE_T handle;
110 int width;
111 int height; /* height of the image (valid pixel data) */
112 int stride; /* bytes */
113 int buffer_height; /* height of the buffer */
114 VC_IMAGE_TYPE_T ifmt;
115};
116
117struct rpi_element {
118 struct wl_list link;
119 struct weston_plane plane;
120 struct rpi_output *output;
121
122 DISPMANX_ELEMENT_HANDLE_T handle;
123 int layer;
124 int need_swap;
125 int single_buffer;
126
127 struct rpi_resource resources[2];
128 struct rpi_resource *front;
129 struct rpi_resource *back;
130 pixman_region32_t prev_damage;
131
132 struct weston_surface *surface;
133 struct wl_listener surface_destroy_listener;
134};
135
136struct rpi_flippipe {
137 int readfd;
138 int writefd;
139 struct wl_event_source *source;
140};
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200141
142struct rpi_output {
143 struct rpi_compositor *compositor;
144 struct weston_output base;
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +0200145 int single_buffer;
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200146
147 struct weston_mode mode;
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +0200148 struct rpi_flippipe flippipe;
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200149
150 DISPMANX_DISPLAY_HANDLE_T display;
151 EGL_DISPMANX_WINDOW_T egl_window;
152 DISPMANX_ELEMENT_HANDLE_T egl_element;
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +0200153
154 struct wl_list element_list; /* struct rpi_element */
155 struct wl_list old_element_list; /* struct rpi_element */
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200156};
157
158struct rpi_seat {
159 struct weston_seat base;
160 struct wl_list devices_list;
161
162 struct udev_monitor *udev_monitor;
163 struct wl_event_source *udev_monitor_source;
164 char *seat_id;
165};
166
167struct rpi_compositor {
168 struct weston_compositor base;
169 uint32_t prev_state;
170
171 struct udev *udev;
172 struct tty *tty;
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +0200173
174 int max_planes; /* per output, really */
175 int single_buffer;
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200176};
177
178static inline struct rpi_output *
179to_rpi_output(struct weston_output *base)
180{
181 return container_of(base, struct rpi_output, base);
182}
183
184static inline struct rpi_seat *
185to_rpi_seat(struct weston_seat *base)
186{
187 return container_of(base, struct rpi_seat, base);
188}
189
190static inline struct rpi_compositor *
191to_rpi_compositor(struct weston_compositor *base)
192{
193 return container_of(base, struct rpi_compositor, base);
194}
195
196static const char *
197egl_error_string(EGLint code)
198{
199#define MYERRCODE(x) case x: return #x;
200 switch (code) {
201 MYERRCODE(EGL_SUCCESS)
202 MYERRCODE(EGL_NOT_INITIALIZED)
203 MYERRCODE(EGL_BAD_ACCESS)
204 MYERRCODE(EGL_BAD_ALLOC)
205 MYERRCODE(EGL_BAD_ATTRIBUTE)
206 MYERRCODE(EGL_BAD_CONTEXT)
207 MYERRCODE(EGL_BAD_CONFIG)
208 MYERRCODE(EGL_BAD_CURRENT_SURFACE)
209 MYERRCODE(EGL_BAD_DISPLAY)
210 MYERRCODE(EGL_BAD_SURFACE)
211 MYERRCODE(EGL_BAD_MATCH)
212 MYERRCODE(EGL_BAD_PARAMETER)
213 MYERRCODE(EGL_BAD_NATIVE_PIXMAP)
214 MYERRCODE(EGL_BAD_NATIVE_WINDOW)
215 MYERRCODE(EGL_CONTEXT_LOST)
216 default:
217 return "unknown";
218 }
219#undef MYERRCODE
220}
221
222static void
223print_egl_error_state(void)
224{
225 EGLint code;
226
227 code = eglGetError();
228 weston_log("EGL error state: %s (0x%04lx)\n",
229 egl_error_string(code), (long)code);
230}
231
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +0200232static inline int
233int_max(int a, int b)
234{
235 return a > b ? a : b;
236}
237
238static void
239rpi_resource_init(struct rpi_resource *resource)
240{
241 resource->handle = DISPMANX_NO_HANDLE;
242}
243
244static void
245rpi_resource_release(struct rpi_resource *resource)
246{
247 if (resource->handle == DISPMANX_NO_HANDLE)
248 return;
249
250 vc_dispmanx_resource_delete(resource->handle);
251 DBG("resource %p release\n", resource);
252 resource->handle = DISPMANX_NO_HANDLE;
253}
254
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200255static int
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +0200256rpi_resource_realloc(struct rpi_resource *resource, VC_IMAGE_TYPE_T ifmt,
257 int width, int height, int stride, int buffer_height)
258{
259 uint32_t dummy;
260
261 if (resource->handle != DISPMANX_NO_HANDLE &&
262 resource->width == width &&
263 resource->height == height &&
264 resource->stride == stride &&
265 resource->buffer_height == buffer_height &&
266 resource->ifmt == ifmt)
267 return 0;
268
269 rpi_resource_release(resource);
270
271 /* NOTE: if stride is not a multiple of 16 pixels in bytes,
272 * the vc_image_* functions may break. Dispmanx elements
273 * should be fine, though. Buffer_height probably has similar
274 * constraints, too.
275 */
276 resource->handle =
277 vc_dispmanx_resource_create(ifmt,
278 width | (stride << 16),
279 height | (buffer_height << 16),
280 &dummy);
281 if (resource->handle == DISPMANX_NO_HANDLE)
282 return -1;
283
284 resource->width = width;
285 resource->height = height;
286 resource->stride = stride;
287 resource->buffer_height = buffer_height;
288 resource->ifmt = ifmt;
289 DBG("resource %p alloc\n", resource);
290 return 0;
291}
292
293static VC_IMAGE_TYPE_T
294shm_buffer_get_vc_format(struct wl_buffer *buffer)
295{
296 switch (wl_shm_buffer_get_format(buffer)) {
297 case WL_SHM_FORMAT_XRGB8888:
298 return VC_IMAGE_XRGB8888;
299 case WL_SHM_FORMAT_ARGB8888:
300 return VC_IMAGE_ARGB8888;
301 default:
302 /* invalid format */
303 return VC_IMAGE_MIN;
304 }
305}
306
307static int
308rpi_resource_update(struct rpi_resource *resource, struct wl_buffer *buffer,
309 pixman_region32_t *region)
310{
311 pixman_region32_t write_region;
312 pixman_box32_t *r;
313 VC_RECT_T rect;
314 VC_IMAGE_TYPE_T ifmt;
315 uint32_t *pixels;
316 int width;
317 int height;
318 int stride;
319 int ret;
320#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
321 int n;
322#endif
323
324 if (!buffer)
325 return -1;
326
327 ifmt = shm_buffer_get_vc_format(buffer);
328 width = wl_shm_buffer_get_width(buffer);
329 height = wl_shm_buffer_get_height(buffer);
330 stride = wl_shm_buffer_get_stride(buffer);
331 pixels = wl_shm_buffer_get_data(buffer);
332
333 if (rpi_resource_realloc(resource, ifmt, width, height,
334 stride, height) < 0)
335 return -1;
336
337 pixman_region32_init(&write_region);
338 pixman_region32_intersect_rect(&write_region, region,
339 0, 0, width, height);
340
341#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
342 /* XXX: Can this do a format conversion, so that scanout does not have to? */
343 r = pixman_region32_rectangles(&write_region, &n);
344 while (n--) {
345 vc_dispmanx_rect_set(&rect, r[n].x1, r[n].y1,
346 r[n].x2 - r[n].x1, r[n].y2 - r[n].y1);
347
348 ret = vc_dispmanx_resource_write_data_rect(resource->handle,
349 ifmt, stride,
350 pixels, &rect,
351 rect.x, rect.y);
352 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
353 rect.width, rect.height, rect.x, rect.y, ret);
354 if (ret)
355 break;
356 }
357#else
358 /* vc_dispmanx_resource_write_data() ignores ifmt,
359 * rect.x, rect.width, and uses stride only for computing
360 * the size of the transfer as rect.height * stride.
361 * Therefore we can only write rows starting at x=0.
362 * To be able to write more than one scanline at a time,
363 * the resource must have been created with the same stride
364 * as used here, and we must write full scanlines.
365 */
366
367 r = pixman_region32_extents(&write_region);
368 vc_dispmanx_rect_set(&rect, 0, r->y1, width, r->y2 - r->y1);
369 ret = vc_dispmanx_resource_write_data(resource->handle, ifmt,
370 stride, pixels, &rect);
371 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
372 width, r->y2 - r->y1, 0, r->y1, ret);
373#endif
374
375 pixman_region32_fini(&write_region);
376
377 return ret ? -1 : 0;
378}
379
380static void
381rpi_element_handle_surface_destroy(struct wl_listener *listener, void *data)
382{
383 struct rpi_element *element =
384 container_of(listener, struct rpi_element,
385 surface_destroy_listener);
386
387 element->surface = NULL;
388}
389
390static struct rpi_element *
391rpi_element_create(struct rpi_output *output, struct weston_surface *surface)
392{
393 struct rpi_element *element;
394
395 element = calloc(1, sizeof *element);
396 if (!element)
397 return NULL;
398
399 element->output = output;
400 element->single_buffer = output->single_buffer;
401 element->handle = DISPMANX_NO_HANDLE;
402 rpi_resource_init(&element->resources[0]);
403 rpi_resource_init(&element->resources[1]);
404 element->front = &element->resources[0];
405
406 if (element->single_buffer) {
407 element->back = element->front;
408 } else {
409 element->back = &element->resources[1];
410 }
411
412 pixman_region32_init(&element->prev_damage);
413
414 weston_plane_init(&element->plane, floor(surface->geometry.x),
415 floor(surface->geometry.y));
416
417 element->surface = surface;
418 element->surface_destroy_listener.notify =
419 rpi_element_handle_surface_destroy;
420 wl_signal_add(&surface->surface.resource.destroy_signal,
421 &element->surface_destroy_listener);
422
423 wl_list_insert(output->element_list.prev, &element->link);
424
425 return element;
426}
427
428static void
429rpi_element_destroy(struct rpi_element *element)
430{
431 struct weston_surface *surface = element->surface;
432
433 if (surface) {
434 if (surface->plane == &element->plane) {
435 /* If a surface, that was on a plane, gets hidden,
436 * it will not appear in the repaint surface list,
437 * is never considered in rpi_output_assign_planes(),
438 * and hence can stay assigned to this element's plane.
439 * We need to reassign it here.
440 */
441 DBG("surface %p (%dx%d@%.1f,%.1f) to primary plane*\n",
442 surface,
443 surface->geometry.width, surface->geometry.height,
444 surface->geometry.x, surface->geometry.y);
445 weston_surface_move_to_plane(surface,
446 &surface->compositor->primary_plane);
447 }
448 wl_list_remove(&element->surface_destroy_listener.link);
449 }
450
451 wl_list_remove(&element->link);
452 weston_plane_release(&element->plane);
453
454 if (element->handle != DISPMANX_NO_HANDLE)
455 weston_log("ERROR rpi: destroying on-screen element\n");
456
457 pixman_region32_fini(&element->prev_damage);
458 rpi_resource_release(&element->resources[0]);
459 rpi_resource_release(&element->resources[1]);
460 DBG("element %p destroyed (%u)\n", element, element->handle);
461
462 free(element);
463}
464
465static void
466rpi_element_reuse(struct rpi_element *element)
467{
468 wl_list_remove(&element->link);
469 wl_list_insert(element->output->element_list.prev, &element->link);
470}
471
472static void
473rpi_element_schedule_destroy(struct rpi_element *element)
474{
475 wl_list_remove(&element->link);
476 wl_list_insert(element->output->old_element_list.prev,
477 &element->link);
478}
479
480static int
481rpi_element_damage(struct rpi_element *element, struct wl_buffer *buffer,
482 pixman_region32_t *damage)
483{
484 pixman_region32_t upload;
485 int ret;
486
487 if (!pixman_region32_not_empty(damage))
488 return 0;
489
490 DBG("element %p update resource %p\n", element, element->back);
491
492 if (element->single_buffer) {
493 ret = rpi_resource_update(element->back, buffer, damage);
494 } else {
495 pixman_region32_init(&upload);
496 pixman_region32_union(&upload, &element->prev_damage, damage);
497 ret = rpi_resource_update(element->back, buffer, &upload);
498 pixman_region32_fini(&upload);
499 }
500
501 pixman_region32_copy(&element->prev_damage, damage);
502 element->need_swap = 1;
503
504 return ret;
505}
506
507static void
508rpi_element_compute_rects(struct rpi_element *element,
509 VC_RECT_T *src_rect, VC_RECT_T *dst_rect)
510{
511 struct weston_output *output = &element->output->base;
512 int src_x, src_y;
513 int dst_x, dst_y;
514 int width, height;
515
516 /* assume element->plane.{x,y} == element->surface->geometry.{x,y} */
517 src_x = 0;
518 src_y = 0;
519 width = element->surface->geometry.width;
520 height = element->surface->geometry.height;
521
522 dst_x = element->plane.x - output->x;
523 dst_y = element->plane.y - output->y;
524
525 if (dst_x < 0) {
526 width += dst_x;
527 src_x -= dst_x;
528 dst_x = 0;
529 }
530
531 if (dst_y < 0) {
532 height += dst_y;
533 src_y -= dst_y;
534 dst_y = 0;
535 }
536
537 width = int_max(width, 0);
538 height = int_max(height, 0);
539
540 /* src_rect is in 16.16, dst_rect is in 32.0 unsigned fixed point */
541 vc_dispmanx_rect_set(src_rect, src_x << 16, src_y << 16,
542 width << 16, height << 16);
543 vc_dispmanx_rect_set(dst_rect, dst_x, dst_y, width, height);
544}
545
546static void
547rpi_element_dmx_add(struct rpi_element *element,
548 DISPMANX_UPDATE_HANDLE_T update, int layer)
549{
550 VC_DISPMANX_ALPHA_T alphasetup = {
551 DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_PREMULT,
552 255, /* opacity 0-255 */
553 0 /* mask resource handle */
554 };
555 VC_RECT_T dst_rect;
556 VC_RECT_T src_rect;
557
558 rpi_element_compute_rects(element, &src_rect, &dst_rect);
559
560 element->handle = vc_dispmanx_element_add(
561 update,
562 element->output->display,
563 layer,
564 &dst_rect,
565 element->back->handle,
566 &src_rect,
567 DISPMANX_PROTECTION_NONE,
568 &alphasetup,
569 NULL /* clamp */,
570 DISPMANX_NO_ROTATE);
571 DBG("element %p add %u\n", element, element->handle);
572}
573
574static void
575rpi_element_dmx_swap(struct rpi_element *element,
576 DISPMANX_UPDATE_HANDLE_T update)
577{
578 VC_RECT_T rect;
579 pixman_box32_t *r;
580
581 /* XXX: skip, iff resource was not reallocated, and single-buffering */
582 vc_dispmanx_element_change_source(update, element->handle,
583 element->back->handle);
584
585 /* This is current damage now, after rpi_assign_plane() */
586 r = pixman_region32_extents(&element->prev_damage);
587
588 vc_dispmanx_rect_set(&rect, r->x1, r->y1,
589 r->x2 - r->x1, r->y2 - r->y1);
590 vc_dispmanx_element_modified(update, element->handle, &rect);
591 DBG("element %p swap\n", element);
592}
593
594static void
595rpi_element_dmx_move(struct rpi_element *element,
596 DISPMANX_UPDATE_HANDLE_T update, int layer)
597{
598 VC_RECT_T dst_rect;
599 VC_RECT_T src_rect;
600
601 /* XXX: return early, if all attributes stay the same */
602
603 rpi_element_compute_rects(element, &src_rect, &dst_rect);
604
605 vc_dispmanx_element_change_attributes(
606 update,
607 element->handle,
608 ELEMENT_CHANGE_LAYER |
609 ELEMENT_CHANGE_DEST_RECT |
610 ELEMENT_CHANGE_SRC_RECT,
611 layer,
612 255,
613 &dst_rect,
614 &src_rect,
615 DISPMANX_NO_HANDLE,
616 DISPMANX_NO_ROTATE);
617 DBG("element %p move\n", element);
618}
619
620static int
621rpi_element_update(struct rpi_element *element,
622 DISPMANX_UPDATE_HANDLE_T update, int layer)
623{
624 struct rpi_resource *tmp;
625
626 if (element->handle == DISPMANX_NO_HANDLE) {
627 /* need_swap is already true, see rpi_assign_plane() */
628
629 rpi_element_dmx_add(element, update, layer);
630 if (element->handle == DISPMANX_NO_HANDLE)
631 weston_log("ERROR rpi: element_add() failed.\n");
632 } else {
633 if (element->need_swap)
634 rpi_element_dmx_swap(element, update);
635 rpi_element_dmx_move(element, update, layer);
636 }
637 element->layer = layer;
638
639 if (element->need_swap) {
640 tmp = element->front;
641 element->front = element->back;
642 element->back = tmp;
643 element->need_swap = 0;
644 DBG("new back %p, new front %p\n",
645 element->back, element->front);
646 }
647
648 return 0;
649}
650
651static void
652rpi_flippipe_update_complete(DISPMANX_UPDATE_HANDLE_T update, void *data)
653{
654 /* This function runs in a different thread. */
655 struct rpi_flippipe *flippipe = data;
656 struct timeval tv;
657 uint64_t time;
658 ssize_t ret;
659
660 /* manufacture flip completion timestamp */
661 /* XXX: use CLOCK_MONOTONIC instead? */
662 gettimeofday(&tv, NULL);
663 time = (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
664
665 ret = write(flippipe->writefd, &time, sizeof time);
666 if (ret != sizeof time)
667 weston_log("ERROR: %s failed to write, ret %zd, errno %d\n",
668 __func__, ret, errno);
669}
670
671static int
672rpi_dispmanx_update_submit(DISPMANX_UPDATE_HANDLE_T update,
673 struct rpi_output *output)
674{
675 /*
676 * The callback registered here will eventually be called
677 * in a different thread context. Therefore we cannot call
678 * the usual functions from rpi_flippipe_update_complete().
679 * Instead, we have a pipe for passing the message from the
680 * thread, waking up the Weston main event loop, calling
681 * rpi_flippipe_handler(), and then ending up in
682 * rpi_output_update_complete() in the main thread context,
683 * where we can do the frame finishing work.
684 */
685 return vc_dispmanx_update_submit(update, rpi_flippipe_update_complete,
686 &output->flippipe);
687}
688
689static void
690rpi_output_update_complete(struct rpi_output *output, uint64_t time);
691
692static int
693rpi_flippipe_handler(int fd, uint32_t mask, void *data)
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200694{
695 struct rpi_output *output = data;
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +0200696 ssize_t ret;
697 uint64_t time;
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200698
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +0200699 if (mask != WL_EVENT_READABLE)
700 weston_log("ERROR: unexpected mask 0x%x in %s\n",
701 mask, __func__);
702
703 ret = read(fd, &time, sizeof time);
704 if (ret != sizeof time) {
705 weston_log("ERROR: %s failed to read, ret %zd, errno %d\n",
706 __func__, ret, errno);
707 }
708
709 rpi_output_update_complete(output, time);
710
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200711 return 1;
712}
713
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +0200714static int
715rpi_flippipe_init(struct rpi_flippipe *flippipe, struct rpi_output *output)
716{
717 struct wl_event_loop *loop;
718 int fd[2];
719
720 if (pipe2(fd, O_CLOEXEC) == -1)
721 return -1;
722
723 flippipe->readfd = fd[0];
724 flippipe->writefd = fd[1];
725
726 loop = wl_display_get_event_loop(output->compositor->base.wl_display);
727 flippipe->source = wl_event_loop_add_fd(loop, flippipe->readfd,
728 WL_EVENT_READABLE,
729 rpi_flippipe_handler, output);
730
731 if (!flippipe->source) {
732 close(flippipe->readfd);
733 close(flippipe->writefd);
734 return -1;
735 }
736
737 return 0;
738}
739
740static void
741rpi_flippipe_release(struct rpi_flippipe *flippipe)
742{
743 wl_event_source_remove(flippipe->source);
744 close(flippipe->readfd);
745 close(flippipe->writefd);
746}
747
748static struct rpi_element *
749find_rpi_element_from_surface(struct weston_surface *surface)
750{
751 struct wl_listener *listener;
752 struct rpi_element *element;
753
754 listener = wl_signal_get(&surface->surface.resource.destroy_signal,
755 rpi_element_handle_surface_destroy);
756 if (!listener)
757 return NULL;
758
759 element = container_of(listener, struct rpi_element,
760 surface_destroy_listener);
761
762 if (element->surface != surface)
763 weston_log("ERROR rpi: sanity check failure in %s.\n",
764 __func__);
765
766 return element;
767}
768
769static struct rpi_element *
770rpi_assign_plane(struct weston_surface *surface, struct rpi_output *output)
771{
772 struct rpi_element *element;
773
774 /* dispmanx elements cannot transform */
775 if (surface->transform.enabled) {
776 /* XXX: inspect the transformation matrix, we might still
777 * be able to put it into an element; scaling, additional
778 * translation (window titlebar context menus?)
779 */
780 DBG("surface %p rejected: transform\n", surface);
781 return NULL;
782 }
783
784 /* only shm surfaces supported */
785 if (surface->buffer && !wl_buffer_is_shm(surface->buffer)) {
786 DBG("surface %p rejected: not shm\n", surface);
787 return NULL;
788 }
789
790 /* check if this surface previously belonged to an element */
791 element = find_rpi_element_from_surface(surface);
792
793 if (element) {
794 rpi_element_reuse(element);
795 element->plane.x = floor(surface->geometry.x);
796 element->plane.y = floor(surface->geometry.y);
797 DBG("surface %p reuse element %p\n", surface, element);
798 } else {
799 if (!surface->buffer) {
800 DBG("surface %p rejected: no buffer\n", surface);
801 return NULL;
802 }
803
804 element = rpi_element_create(output, surface);
805 DBG("element %p created\n", element);
806 }
807
808 if (!element) {
809 DBG("surface %p rejected: no element\n", surface);
810 return NULL;
811 }
812
813 return element;
814}
815
816static void
817rpi_output_assign_planes(struct weston_output *base)
818{
819 struct rpi_output *output = to_rpi_output(base);
820 struct rpi_compositor *compositor = output->compositor;
821 struct weston_surface *surface;
822 pixman_region32_t overlap;
823 pixman_region32_t surface_overlap;
824 struct rpi_element *element;
825 int n = 0;
826
827 /* Construct the list of rpi_elements to be used into
828 * output->element_list, which is empty right now.
829 * Re-used elements are moved from old_element_list to
830 * element_list. */
831
832 DBG("%s\n", __func__);
833
834 pixman_region32_init(&overlap);
835 wl_list_for_each(surface, &compositor->base.surface_list, link) {
836 pixman_region32_init(&surface_overlap);
837 pixman_region32_intersect(&surface_overlap, &overlap,
838 &surface->transform.boundingbox);
839
840 element = NULL;
841 if (!pixman_region32_not_empty(&surface_overlap) &&
842 n < compositor->max_planes)
843 element = rpi_assign_plane(surface, output);
844
845 if (element) {
846 weston_surface_move_to_plane(surface, &element->plane);
847 DBG("surface %p (%dx%d@%.1f,%.1f) to element %p\n",
848 surface,
849 surface->geometry.width, surface->geometry.height,
850 surface->geometry.x, surface->geometry.y, element);
851
852 /* weston_surface_move_to_plane() does full-surface
853 * damage, if the plane is new, so no need to force
854 * initial resource update.
855 */
856 if (rpi_element_damage(element, surface->buffer,
857 &surface->damage) < 0) {
858 rpi_element_schedule_destroy(element);
859 DBG("surface %p rejected: resource update failed\n",
860 surface);
861 element = NULL;
862 } else {
863 n++;
864 }
865 }
866
867 if (!element) {
868 weston_surface_move_to_plane(surface,
869 &compositor->base.primary_plane);
870 DBG("surface %p (%dx%d@%.1f,%.1f) to primary plane\n",
871 surface,
872 surface->geometry.width, surface->geometry.height,
873 surface->geometry.x, surface->geometry.y);
874 pixman_region32_union(&overlap, &overlap,
875 &surface->transform.boundingbox);
876 }
877
878 pixman_region32_fini(&surface_overlap);
879 }
880 pixman_region32_fini(&overlap);
881}
882
883static void
884rpi_remove_elements(struct wl_list *element_list,
885 DISPMANX_UPDATE_HANDLE_T update)
886{
887 struct rpi_element *element;
888
889 wl_list_for_each(element, element_list, link) {
890 if (element->handle == DISPMANX_NO_HANDLE)
891 continue;
892
893 vc_dispmanx_element_remove(update, element->handle);
894 DBG("element %p remove %u\n", element, element->handle);
895 element->handle = DISPMANX_NO_HANDLE;
896 }
897}
898
899static void
900rpi_output_destroy_old_elements(struct rpi_output *output)
901{
902 struct rpi_element *element, *tmp;
903
904 wl_list_for_each_safe(element, tmp, &output->old_element_list, link) {
905 if (element->handle != DISPMANX_NO_HANDLE)
906 continue;
907
908 rpi_element_destroy(element);
909 }
910}
911
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200912static void
913rpi_output_repaint(struct weston_output *base, pixman_region32_t *damage)
914{
915 struct rpi_output *output = to_rpi_output(base);
916 struct rpi_compositor *compositor = output->compositor;
Ander Conselvan de Oliveira0a887722012-11-22 15:57:00 +0200917 struct weston_plane *primary_plane = &compositor->base.primary_plane;
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +0200918 struct rpi_element *element;
919 DISPMANX_UPDATE_HANDLE_T update;
920 int layer = 10000;
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200921
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +0200922 DBG("%s\n", __func__);
923
924 update = vc_dispmanx_update_start(0);
925
926 /* update all live elements */
927 wl_list_for_each(element, &output->element_list, link) {
928 if (rpi_element_update(element, update, layer--) < 0)
929 weston_log("ERROR rpi: element update failed.\n");
930 }
931
932 /* remove all unused elements */
933 rpi_remove_elements(&output->old_element_list, update);
934
935 /* schedule callback to rpi_output_update_complete() */
936 rpi_dispmanx_update_submit(update, output);
937
938 /* XXX: if there is anything to composite in GL,
939 * framerate seems to suffer */
940 /* XXX: optimise the renderer for the case of nothing to render */
941 /* XXX: if nothing to render, remove the element...
942 * but how, is destroying the EGLSurface a bad performance hit?
943 */
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200944 compositor->base.renderer->repaint_output(&output->base, damage);
945
Ander Conselvan de Oliveira0a887722012-11-22 15:57:00 +0200946 pixman_region32_subtract(&primary_plane->damage,
947 &primary_plane->damage, damage);
948
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +0200949 /* Move the list of elements into the old_element_list. */
950 wl_list_insert_list(&output->old_element_list, &output->element_list);
951 wl_list_init(&output->element_list);
952}
953
954static void
955rpi_output_update_complete(struct rpi_output *output, uint64_t time)
956{
957 rpi_output_destroy_old_elements(output);
958 weston_output_finish_frame(&output->base, time);
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200959}
960
961static void
962rpi_output_destroy(struct weston_output *base)
963{
964 struct rpi_output *output = to_rpi_output(base);
965 DISPMANX_UPDATE_HANDLE_T update;
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +0200966 struct rpi_element *element, *tmp;
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200967
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +0200968 DBG("%s\n", __func__);
969
970 rpi_flippipe_release(&output->flippipe);
971
972 update = vc_dispmanx_update_start(0);
973 rpi_remove_elements(&output->element_list, update);
974 rpi_remove_elements(&output->old_element_list, update);
975 vc_dispmanx_element_remove(update, output->egl_element);
976 vc_dispmanx_update_submit_sync(update);
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200977
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100978 gl_renderer_output_destroy(base);
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200979
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +0200980 wl_list_for_each_safe(element, tmp, &output->element_list, link)
981 rpi_element_destroy(element);
982
983 wl_list_for_each_safe(element, tmp, &output->old_element_list, link)
984 rpi_element_destroy(element);
985
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200986 wl_list_remove(&output->base.link);
987 weston_output_destroy(&output->base);
988
Pekka Paalanene8de35c2012-11-07 12:25:14 +0200989 vc_dispmanx_display_close(output->display);
990
991 free(output);
992}
993
994static int
995rpi_output_create(struct rpi_compositor *compositor)
996{
997 struct rpi_output *output;
998 DISPMANX_MODEINFO_T modeinfo;
999 DISPMANX_UPDATE_HANDLE_T update;
1000 VC_RECT_T dst_rect;
1001 VC_RECT_T src_rect;
1002 int ret;
1003 float mm_width, mm_height;
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +02001004 VC_DISPMANX_ALPHA_T alphasetup = {
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001005 DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
1006 255, /* opacity 0-255 */
1007 0 /* mask resource handle */
1008 };
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001009
1010 output = calloc(1, sizeof *output);
1011 if (!output)
1012 return -1;
1013
1014 output->compositor = compositor;
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +02001015 output->single_buffer = compositor->single_buffer;
1016 wl_list_init(&output->element_list);
1017 wl_list_init(&output->old_element_list);
1018
1019 if (rpi_flippipe_init(&output->flippipe, output) < 0) {
1020 weston_log("Creating message pipe failed.\n");
1021 goto out_free;
1022 }
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001023
1024 output->display = vc_dispmanx_display_open(DISPMANX_ID_HDMI);
1025 if (!output->display) {
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +02001026 weston_log("Failed to open dispmanx HDMI display.\n");
1027 goto out_pipe;
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001028 }
1029
1030 ret = vc_dispmanx_display_get_info(output->display, &modeinfo);
1031 if (ret < 0) {
1032 weston_log("Failed to get display mode information.\n");
1033 goto out_dmx_close;
1034 }
1035
1036 vc_dispmanx_rect_set(&dst_rect, 0, 0, modeinfo.width, modeinfo.height);
1037 vc_dispmanx_rect_set(&src_rect, 0, 0,
1038 modeinfo.width << 16, modeinfo.height << 16);
1039
1040 update = vc_dispmanx_update_start(0);
1041 output->egl_element = vc_dispmanx_element_add(update,
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +02001042 output->display,
1043 0 /* layer */,
1044 &dst_rect,
1045 0 /* src resource */,
1046 &src_rect,
1047 DISPMANX_PROTECTION_NONE,
1048 &alphasetup,
1049 NULL /* clamp */,
1050 DISPMANX_NO_ROTATE);
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001051 vc_dispmanx_update_submit_sync(update);
1052
1053 output->egl_window.element = output->egl_element;
1054 output->egl_window.width = modeinfo.width;
1055 output->egl_window.height = modeinfo.height;
1056
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001057 output->base.repaint = rpi_output_repaint;
1058 output->base.destroy = rpi_output_destroy;
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +02001059 if (compositor->max_planes > 0)
1060 output->base.assign_planes = rpi_output_assign_planes;
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001061 output->base.set_backlight = NULL;
1062 output->base.set_dpms = NULL;
1063 output->base.switch_mode = NULL;
1064
1065 /* XXX: use tvservice to get information from and control the
1066 * HDMI and SDTV outputs. See:
1067 * /opt/vc/include/interface/vmcs_host/vc_tvservice.h
1068 */
1069
1070 /* only one static mode in list */
1071 output->mode.flags =
1072 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1073 output->mode.width = modeinfo.width;
1074 output->mode.height = modeinfo.height;
1075 output->mode.refresh = 60000;
1076 wl_list_init(&output->base.mode_list);
1077 wl_list_insert(&output->base.mode_list, &output->mode.link);
1078
1079 output->base.current = &output->mode;
1080 output->base.origin = &output->mode;
1081 output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
1082 output->base.make = "unknown";
1083 output->base.model = "unknown";
1084
1085 /* guess 96 dpi */
1086 mm_width = modeinfo.width * (25.4f / 96.0f);
1087 mm_height = modeinfo.height * (25.4f / 96.0f);
1088
1089 weston_output_init(&output->base, &compositor->base,
1090 0, 0, round(mm_width), round(mm_height),
1091 WL_OUTPUT_TRANSFORM_NORMAL);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001092
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001093 if (gl_renderer_output_create(&output->base,
John Kåre Alsaker94659272012-11-13 19:10:18 +01001094 (EGLNativeWindowType)&output->egl_window) < 0)
1095 goto out_output;
1096
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001097 if (!eglSurfaceAttrib(gl_renderer_display(&compositor->base),
1098 gl_renderer_output_surface(&output->base),
John Kåre Alsaker94659272012-11-13 19:10:18 +01001099 EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED)) {
1100 print_egl_error_state();
1101 weston_log("Failed to set swap behaviour to preserved.\n");
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001102 goto out_gl;
John Kåre Alsaker94659272012-11-13 19:10:18 +01001103 }
1104
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001105 wl_list_insert(compositor->base.output_list.prev, &output->base.link);
1106
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001107 weston_log("Raspberry Pi HDMI output %dx%d px\n",
1108 output->mode.width, output->mode.height);
1109 weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
1110 output->mode.refresh / 1000);
1111
1112 return 0;
1113
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001114out_gl:
1115 gl_renderer_output_destroy(&output->base);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001116out_output:
1117 weston_output_destroy(&output->base);
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +02001118 update = vc_dispmanx_update_start(0);
1119 vc_dispmanx_element_remove(update, output->egl_element);
1120 vc_dispmanx_update_submit_sync(update);
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001121
1122out_dmx_close:
1123 vc_dispmanx_display_close(output->display);
1124
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +02001125out_pipe:
1126 rpi_flippipe_release(&output->flippipe);
1127
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001128out_free:
1129 free(output);
1130 return -1;
1131}
1132
1133static void
1134rpi_led_update(struct weston_seat *seat_base, enum weston_led leds)
1135{
1136 struct rpi_seat *seat = to_rpi_seat(seat_base);
1137 struct evdev_device *device;
1138
1139 wl_list_for_each(device, &seat->devices_list, link)
1140 evdev_led_update(device, leds);
1141}
1142
1143static const char default_seat[] = "seat0";
1144
1145static void
1146device_added(struct udev_device *udev_device, struct rpi_seat *master)
1147{
1148 struct evdev_device *device;
1149 const char *devnode;
1150 const char *device_seat;
1151 int fd;
1152
1153 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1154 if (!device_seat)
1155 device_seat = default_seat;
1156
1157 if (strcmp(device_seat, master->seat_id))
1158 return;
1159
1160 devnode = udev_device_get_devnode(udev_device);
1161
1162 /* Use non-blocking mode so that we can loop on read on
1163 * evdev_device_data() until all events on the fd are
1164 * read. mtdev_get() also expects this. */
1165 fd = open(devnode, O_RDWR | O_NONBLOCK | O_CLOEXEC);
1166 if (fd < 0) {
1167 weston_log("opening input device '%s' failed.\n", devnode);
1168 return;
1169 }
1170
1171 device = evdev_device_create(&master->base, devnode, fd);
1172 if (!device) {
1173 close(fd);
1174 weston_log("not using input device '%s'.\n", devnode);
1175 return;
1176 }
1177
1178 wl_list_insert(master->devices_list.prev, &device->link);
1179}
1180
1181static void
1182evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1183{
1184 struct rpi_seat *seat = to_rpi_seat(seat_base);
1185 struct udev_enumerate *e;
1186 struct udev_list_entry *entry;
1187 struct udev_device *device;
1188 const char *path, *sysname;
1189
1190 e = udev_enumerate_new(udev);
1191 udev_enumerate_add_match_subsystem(e, "input");
1192 udev_enumerate_scan_devices(e);
1193 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1194 path = udev_list_entry_get_name(entry);
1195 device = udev_device_new_from_syspath(udev, path);
1196
1197 sysname = udev_device_get_sysname(device);
1198 if (strncmp("event", sysname, 5) != 0) {
1199 udev_device_unref(device);
1200 continue;
1201 }
1202
1203 device_added(device, seat);
1204
1205 udev_device_unref(device);
1206 }
1207 udev_enumerate_unref(e);
1208
1209 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1210
1211 if (wl_list_empty(&seat->devices_list)) {
1212 weston_log(
1213 "warning: no input devices on entering Weston. "
1214 "Possible causes:\n"
1215 "\t- no permissions to read /dev/input/event*\n"
1216 "\t- seats misconfigured "
1217 "(Weston backend option 'seat', "
1218 "udev device property ID_SEAT)\n");
1219 }
1220}
1221
1222static int
1223evdev_udev_handler(int fd, uint32_t mask, void *data)
1224{
1225 struct rpi_seat *seat = data;
1226 struct udev_device *udev_device;
1227 struct evdev_device *device, *next;
1228 const char *action;
1229 const char *devnode;
1230
1231 udev_device = udev_monitor_receive_device(seat->udev_monitor);
1232 if (!udev_device)
1233 return 1;
1234
1235 action = udev_device_get_action(udev_device);
1236 if (!action)
1237 goto out;
1238
1239 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1240 goto out;
1241
1242 if (!strcmp(action, "add")) {
1243 device_added(udev_device, seat);
1244 }
1245 else if (!strcmp(action, "remove")) {
1246 devnode = udev_device_get_devnode(udev_device);
1247 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1248 if (!strcmp(device->devnode, devnode)) {
1249 weston_log("input device %s, %s removed\n",
1250 device->devname, device->devnode);
1251 evdev_device_destroy(device);
1252 break;
1253 }
1254 }
1255
1256out:
1257 udev_device_unref(udev_device);
1258
1259 return 0;
1260}
1261
1262static int
1263evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1264{
1265 struct rpi_seat *master = to_rpi_seat(seat_base);
1266 struct wl_event_loop *loop;
1267 struct weston_compositor *c = master->base.compositor;
1268 int fd;
1269
1270 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1271 if (!master->udev_monitor) {
1272 weston_log("udev: failed to create the udev monitor\n");
1273 return 0;
1274 }
1275
1276 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1277 "input", NULL);
1278
1279 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1280 weston_log("udev: failed to bind the udev monitor\n");
1281 udev_monitor_unref(master->udev_monitor);
1282 return 0;
1283 }
1284
1285 loop = wl_display_get_event_loop(c->wl_display);
1286 fd = udev_monitor_get_fd(master->udev_monitor);
1287 master->udev_monitor_source =
1288 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1289 evdev_udev_handler, master);
1290 if (!master->udev_monitor_source) {
1291 udev_monitor_unref(master->udev_monitor);
1292 return 0;
1293 }
1294
1295 return 1;
1296}
1297
1298static void
1299evdev_disable_udev_monitor(struct weston_seat *seat_base)
1300{
1301 struct rpi_seat *seat = to_rpi_seat(seat_base);
1302
1303 if (!seat->udev_monitor)
1304 return;
1305
1306 udev_monitor_unref(seat->udev_monitor);
1307 seat->udev_monitor = NULL;
1308 wl_event_source_remove(seat->udev_monitor_source);
1309 seat->udev_monitor_source = NULL;
1310}
1311
1312static void
1313evdev_input_create(struct weston_compositor *c, struct udev *udev,
1314 const char *seat_id)
1315{
1316 struct rpi_seat *seat;
1317
1318 seat = malloc(sizeof *seat);
1319 if (seat == NULL)
1320 return;
1321
1322 memset(seat, 0, sizeof *seat);
1323 weston_seat_init(&seat->base, c);
1324 seat->base.led_update = rpi_led_update;
1325
1326 wl_list_init(&seat->devices_list);
1327 seat->seat_id = strdup(seat_id);
1328 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1329 free(seat->seat_id);
1330 free(seat);
1331 return;
1332 }
1333
1334 evdev_add_devices(udev, &seat->base);
1335}
1336
1337static void
1338evdev_remove_devices(struct weston_seat *seat_base)
1339{
1340 struct rpi_seat *seat = to_rpi_seat(seat_base);
1341 struct evdev_device *device, *next;
1342
1343 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1344 evdev_device_destroy(device);
1345
1346 if (seat->base.seat.keyboard)
1347 notify_keyboard_focus_out(&seat->base);
1348}
1349
1350static void
1351evdev_input_destroy(struct weston_seat *seat_base)
1352{
1353 struct rpi_seat *seat = to_rpi_seat(seat_base);
1354
1355 evdev_remove_devices(seat_base);
1356 evdev_disable_udev_monitor(&seat->base);
1357
1358 weston_seat_release(seat_base);
1359 free(seat->seat_id);
1360 free(seat);
1361}
1362
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001363static void
1364rpi_compositor_destroy(struct weston_compositor *base)
1365{
1366 struct rpi_compositor *compositor = to_rpi_compositor(base);
1367 struct weston_seat *seat, *next;
1368
1369 wl_list_for_each_safe(seat, next, &compositor->base.seat_list, link)
1370 evdev_input_destroy(seat);
1371
1372 /* destroys outputs, too */
1373 weston_compositor_shutdown(&compositor->base);
1374
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001375 gl_renderer_destroy(&compositor->base);
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001376 tty_destroy(compositor->tty);
1377
1378 bcm_host_deinit();
1379 free(compositor);
1380}
1381
1382static void
1383vt_func(struct weston_compositor *base, int event)
1384{
1385 struct rpi_compositor *compositor = to_rpi_compositor(base);
1386 struct weston_seat *seat;
1387 struct weston_output *output;
1388
1389 switch (event) {
1390 case TTY_ENTER_VT:
1391 weston_log("entering VT\n");
1392 compositor->base.focus = 1;
1393 compositor->base.state = compositor->prev_state;
1394 weston_compositor_damage_all(&compositor->base);
1395 wl_list_for_each(seat, &compositor->base.seat_list, link) {
1396 evdev_add_devices(compositor->udev, seat);
1397 evdev_enable_udev_monitor(compositor->udev, seat);
1398 }
1399 break;
1400 case TTY_LEAVE_VT:
1401 weston_log("leaving VT\n");
1402 wl_list_for_each(seat, &compositor->base.seat_list, link) {
1403 evdev_disable_udev_monitor(seat);
1404 evdev_remove_devices(seat);
1405 }
1406
1407 compositor->base.focus = 0;
1408 compositor->prev_state = compositor->base.state;
1409 compositor->base.state = WESTON_COMPOSITOR_SLEEPING;
1410
1411 /* If we have a repaint scheduled (either from a
1412 * pending pageflip or the idle handler), make sure we
1413 * cancel that so we don't try to pageflip when we're
1414 * vt switched away. The SLEEPING state will prevent
1415 * further attemps at repainting. When we switch
1416 * back, we schedule a repaint, which will process
1417 * pending frame callbacks. */
1418
1419 wl_list_for_each(output,
1420 &compositor->base.output_list, link) {
1421 output->repaint_needed = 0;
1422 }
1423
1424 break;
1425 };
1426}
1427
1428static void
1429rpi_restore(struct weston_compositor *base)
1430{
1431 struct rpi_compositor *compositor = to_rpi_compositor(base);
1432
1433 tty_reset(compositor->tty);
1434}
1435
1436static void
1437switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
1438{
1439 struct rpi_compositor *ec = data;
1440
1441 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
1442}
1443
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +02001444struct rpi_parameters {
1445 int tty;
1446 int max_planes;
1447 int single_buffer;
1448};
1449
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001450static struct weston_compositor *
1451rpi_compositor_create(struct wl_display *display, int argc, char *argv[],
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +02001452 const char *config_file, struct rpi_parameters *param)
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001453{
1454 struct rpi_compositor *compositor;
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001455 const char *seat = default_seat;
1456 uint32_t key;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001457 static const EGLint config_attrs[] = {
1458 EGL_SURFACE_TYPE, EGL_WINDOW_BIT |
1459 EGL_SWAP_BEHAVIOR_PRESERVED_BIT,
1460 EGL_RED_SIZE, 1,
1461 EGL_GREEN_SIZE, 1,
1462 EGL_BLUE_SIZE, 1,
1463 EGL_ALPHA_SIZE, 0,
1464 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1465 EGL_NONE
1466 };
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001467
1468 weston_log("initializing Raspberry Pi backend\n");
1469
1470 compositor = calloc(1, sizeof *compositor);
1471 if (compositor == NULL)
1472 return NULL;
1473
1474 if (weston_compositor_init(&compositor->base, display, argc, argv,
1475 config_file) < 0)
1476 goto out_free;
1477
1478 compositor->udev = udev_new();
1479 if (compositor->udev == NULL) {
1480 weston_log("Failed to initialize udev context.\n");
1481 goto out_compositor;
1482 }
1483
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +02001484 compositor->tty = tty_create(&compositor->base, vt_func, param->tty);
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001485 if (!compositor->tty) {
1486 weston_log("Failed to initialize tty.\n");
1487 goto out_udev;
1488 }
1489
1490 compositor->base.destroy = rpi_compositor_destroy;
1491 compositor->base.restore = rpi_restore;
1492
1493 compositor->base.focus = 1;
1494 compositor->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +02001495 compositor->max_planes = int_max(param->max_planes, 0);
1496 compositor->single_buffer = param->single_buffer;
1497
1498 weston_log("Maximum number of additional Dispmanx planes: %d\n",
1499 compositor->max_planes);
1500 weston_log("Dispmanx planes are %s buffered.\n",
1501 compositor->single_buffer ? "single" : "double");
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001502
1503 for (key = KEY_F1; key < KEY_F9; key++)
1504 weston_compositor_add_key_binding(&compositor->base, key,
1505 MODIFIER_CTRL | MODIFIER_ALT,
1506 switch_vt_binding, compositor);
1507
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +02001508 /*
1509 * bcm_host_init() creates threads.
1510 * Therefore we must have all signal handlers set and signals blocked
1511 * before calling it. Otherwise the signals may end in the bcm
1512 * threads and cause the default behaviour there. For instance,
1513 * SIGUSR1 used for VT switching caused Weston to terminate there.
1514 */
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001515 bcm_host_init();
1516
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001517 if (gl_renderer_create(&compositor->base, EGL_DEFAULT_DISPLAY,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001518 config_attrs, NULL) < 0)
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001519 goto out_tty;
1520
1521 if (rpi_output_create(compositor) < 0)
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001522 goto out_gl;
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001523
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001524 evdev_input_create(&compositor->base, compositor->udev, seat);
1525
1526 return &compositor->base;
1527
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001528out_gl:
1529 gl_renderer_destroy(&compositor->base);
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001530
1531out_tty:
1532 tty_destroy(compositor->tty);
1533
1534out_udev:
1535 udev_unref(compositor->udev);
1536
1537out_compositor:
1538 weston_compositor_shutdown(&compositor->base);
1539
1540out_free:
1541 bcm_host_deinit();
1542 free(compositor);
1543
1544 return NULL;
1545}
1546
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +02001547/*
1548 * If you have a recent enough firmware in Raspberry Pi, that
1549 * supports falling back to off-line hardware compositing, and
1550 * you have enabled it with dispmanx_offline=1 in /boot/config.txt,
1551 * then VideoCore should be able to handle almost 100 Dispmanx
1552 * elements. Therefore use 80 as the default limit.
1553 *
1554 * If you don't have off-line compositing support, this would be
1555 * better as something like 10. Failing on-line compositing may
1556 * show up as visible glitches, HDMI blanking, or invisible surfaces.
1557 *
1558 * When the max-planes number is reached, rpi-backend will start
1559 * to fall back to GLESv2 compositing.
1560 */
1561#define DEFAULT_MAX_PLANES 80
1562
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001563WL_EXPORT struct weston_compositor *
1564backend_init(struct wl_display *display, int argc, char *argv[],
1565 const char *config_file)
1566{
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +02001567 struct rpi_parameters param = {
1568 .tty = 0, /* default to current tty */
1569 .max_planes = DEFAULT_MAX_PLANES,
1570 .single_buffer = 0,
1571 };
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001572
1573 const struct weston_option rpi_options[] = {
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +02001574 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
1575 { WESTON_OPTION_INTEGER, "max-planes", 0, &param.max_planes },
1576 { WESTON_OPTION_BOOLEAN, "single-buffer", 0,
1577 &param.single_buffer },
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001578 };
1579
1580 parse_options(rpi_options, ARRAY_LENGTH(rpi_options), argc, argv);
1581
Pekka Paalanen7fb46fb2012-11-07 12:25:15 +02001582 return rpi_compositor_create(display, argc, argv, config_file, &param);
Pekka Paalanene8de35c2012-11-07 12:25:14 +02001583}