2 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
4 * Copyright © 2012 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.
32 #include <sys/types.h>
41 # include <bcm_host.h>
43 # include "rpi-bcm-stubs.h"
46 #include "compositor.h"
47 #include "gl-renderer.h"
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.
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
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
69 * A resource may be destroyed only, when the update removing the element has
70 * completed. Otherwise you risk showing an incomplete composition.
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.
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.
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)
94 /* Enabling this debugging incurs a significant performance hit */
97 weston_log(__VA_ARGS__)
99 #define DBG(...) do {} while (0)
102 /* If we had a fully featured vc_dispmanx_resource_write_data()... */
103 /*#define HAVE_RESOURCE_WRITE_DATA_RECT 1*/
105 struct rpi_compositor;
108 struct rpi_resource {
109 DISPMANX_RESOURCE_HANDLE_T handle;
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;
119 struct weston_plane plane;
120 struct rpi_output *output;
122 DISPMANX_ELEMENT_HANDLE_T handle;
127 struct rpi_resource resources[2];
128 struct rpi_resource *front;
129 struct rpi_resource *back;
130 pixman_region32_t prev_damage;
132 struct weston_surface *surface;
133 struct wl_listener surface_destroy_listener;
136 struct rpi_flippipe {
139 struct wl_event_source *source;
143 struct rpi_compositor *compositor;
144 struct weston_output base;
147 struct weston_mode mode;
148 struct rpi_flippipe flippipe;
150 DISPMANX_DISPLAY_HANDLE_T display;
151 EGL_DISPMANX_WINDOW_T egl_window;
152 DISPMANX_ELEMENT_HANDLE_T egl_element;
154 struct wl_list element_list; /* struct rpi_element */
155 struct wl_list old_element_list; /* struct rpi_element */
159 struct weston_seat base;
160 struct wl_list devices_list;
162 struct udev_monitor *udev_monitor;
163 struct wl_event_source *udev_monitor_source;
167 struct rpi_compositor {
168 struct weston_compositor base;
174 int max_planes; /* per output, really */
178 static inline struct rpi_output *
179 to_rpi_output(struct weston_output *base)
181 return container_of(base, struct rpi_output, base);
184 static inline struct rpi_seat *
185 to_rpi_seat(struct weston_seat *base)
187 return container_of(base, struct rpi_seat, base);
190 static inline struct rpi_compositor *
191 to_rpi_compositor(struct weston_compositor *base)
193 return container_of(base, struct rpi_compositor, base);
197 int_max(int a, int b)
199 return a > b ? a : b;
203 rpi_resource_init(struct rpi_resource *resource)
205 resource->handle = DISPMANX_NO_HANDLE;
209 rpi_resource_release(struct rpi_resource *resource)
211 if (resource->handle == DISPMANX_NO_HANDLE)
214 vc_dispmanx_resource_delete(resource->handle);
215 DBG("resource %p release\n", resource);
216 resource->handle = DISPMANX_NO_HANDLE;
220 rpi_resource_realloc(struct rpi_resource *resource, VC_IMAGE_TYPE_T ifmt,
221 int width, int height, int stride, int buffer_height)
225 if (resource->handle != DISPMANX_NO_HANDLE &&
226 resource->width == width &&
227 resource->height == height &&
228 resource->stride == stride &&
229 resource->buffer_height == buffer_height &&
230 resource->ifmt == ifmt)
233 rpi_resource_release(resource);
235 /* NOTE: if stride is not a multiple of 16 pixels in bytes,
236 * the vc_image_* functions may break. Dispmanx elements
237 * should be fine, though. Buffer_height probably has similar
241 vc_dispmanx_resource_create(ifmt,
242 width | (stride << 16),
243 height | (buffer_height << 16),
245 if (resource->handle == DISPMANX_NO_HANDLE)
248 resource->width = width;
249 resource->height = height;
250 resource->stride = stride;
251 resource->buffer_height = buffer_height;
252 resource->ifmt = ifmt;
253 DBG("resource %p alloc\n", resource);
257 static VC_IMAGE_TYPE_T
258 shm_buffer_get_vc_format(struct wl_buffer *buffer)
260 switch (wl_shm_buffer_get_format(buffer)) {
261 case WL_SHM_FORMAT_XRGB8888:
262 return VC_IMAGE_XRGB8888;
263 case WL_SHM_FORMAT_ARGB8888:
264 return VC_IMAGE_ARGB8888;
272 rpi_resource_update(struct rpi_resource *resource, struct wl_buffer *buffer,
273 pixman_region32_t *region)
275 pixman_region32_t write_region;
278 VC_IMAGE_TYPE_T ifmt;
284 #ifdef HAVE_RESOURCE_WRITE_DATA_RECT
291 ifmt = shm_buffer_get_vc_format(buffer);
292 width = wl_shm_buffer_get_width(buffer);
293 height = wl_shm_buffer_get_height(buffer);
294 stride = wl_shm_buffer_get_stride(buffer);
295 pixels = wl_shm_buffer_get_data(buffer);
297 if (rpi_resource_realloc(resource, ifmt, width, height,
301 pixman_region32_init(&write_region);
302 pixman_region32_intersect_rect(&write_region, region,
303 0, 0, width, height);
305 #ifdef HAVE_RESOURCE_WRITE_DATA_RECT
306 /* XXX: Can this do a format conversion, so that scanout does not have to? */
307 r = pixman_region32_rectangles(&write_region, &n);
309 vc_dispmanx_rect_set(&rect, r[n].x1, r[n].y1,
310 r[n].x2 - r[n].x1, r[n].y2 - r[n].y1);
312 ret = vc_dispmanx_resource_write_data_rect(resource->handle,
316 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
317 rect.width, rect.height, rect.x, rect.y, ret);
322 /* vc_dispmanx_resource_write_data() ignores ifmt,
323 * rect.x, rect.width, and uses stride only for computing
324 * the size of the transfer as rect.height * stride.
325 * Therefore we can only write rows starting at x=0.
326 * To be able to write more than one scanline at a time,
327 * the resource must have been created with the same stride
328 * as used here, and we must write full scanlines.
331 r = pixman_region32_extents(&write_region);
332 vc_dispmanx_rect_set(&rect, 0, r->y1, width, r->y2 - r->y1);
333 ret = vc_dispmanx_resource_write_data(resource->handle, ifmt,
334 stride, pixels, &rect);
335 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
336 width, r->y2 - r->y1, 0, r->y1, ret);
339 pixman_region32_fini(&write_region);
345 rpi_element_handle_surface_destroy(struct wl_listener *listener, void *data)
347 struct rpi_element *element =
348 container_of(listener, struct rpi_element,
349 surface_destroy_listener);
351 element->surface = NULL;
354 static struct rpi_element *
355 rpi_element_create(struct rpi_output *output, struct weston_surface *surface)
357 struct rpi_element *element;
359 element = calloc(1, sizeof *element);
363 element->output = output;
364 element->single_buffer = output->single_buffer;
365 element->handle = DISPMANX_NO_HANDLE;
366 rpi_resource_init(&element->resources[0]);
367 rpi_resource_init(&element->resources[1]);
368 element->front = &element->resources[0];
370 if (element->single_buffer) {
371 element->back = element->front;
373 element->back = &element->resources[1];
376 pixman_region32_init(&element->prev_damage);
378 weston_plane_init(&element->plane, floor(surface->geometry.x),
379 floor(surface->geometry.y));
381 element->surface = surface;
382 element->surface_destroy_listener.notify =
383 rpi_element_handle_surface_destroy;
384 wl_signal_add(&surface->surface.resource.destroy_signal,
385 &element->surface_destroy_listener);
387 wl_list_insert(output->element_list.prev, &element->link);
393 rpi_element_destroy(struct rpi_element *element)
395 struct weston_surface *surface = element->surface;
398 if (surface->plane == &element->plane) {
399 /* If a surface, that was on a plane, gets hidden,
400 * it will not appear in the repaint surface list,
401 * is never considered in rpi_output_assign_planes(),
402 * and hence can stay assigned to this element's plane.
403 * We need to reassign it here.
405 DBG("surface %p (%dx%d@%.1f,%.1f) to primary plane*\n",
407 surface->geometry.width, surface->geometry.height,
408 surface->geometry.x, surface->geometry.y);
409 weston_surface_move_to_plane(surface,
410 &surface->compositor->primary_plane);
412 wl_list_remove(&element->surface_destroy_listener.link);
415 wl_list_remove(&element->link);
416 weston_plane_release(&element->plane);
418 if (element->handle != DISPMANX_NO_HANDLE)
419 weston_log("ERROR rpi: destroying on-screen element\n");
421 pixman_region32_fini(&element->prev_damage);
422 rpi_resource_release(&element->resources[0]);
423 rpi_resource_release(&element->resources[1]);
424 DBG("element %p destroyed (%u)\n", element, element->handle);
430 rpi_element_reuse(struct rpi_element *element)
432 wl_list_remove(&element->link);
433 wl_list_insert(element->output->element_list.prev, &element->link);
437 rpi_element_schedule_destroy(struct rpi_element *element)
439 wl_list_remove(&element->link);
440 wl_list_insert(element->output->old_element_list.prev,
445 rpi_element_damage(struct rpi_element *element, struct wl_buffer *buffer,
446 pixman_region32_t *damage)
448 pixman_region32_t upload;
451 if (!pixman_region32_not_empty(damage))
454 DBG("element %p update resource %p\n", element, element->back);
456 if (element->single_buffer) {
457 ret = rpi_resource_update(element->back, buffer, damage);
459 pixman_region32_init(&upload);
460 pixman_region32_union(&upload, &element->prev_damage, damage);
461 ret = rpi_resource_update(element->back, buffer, &upload);
462 pixman_region32_fini(&upload);
465 pixman_region32_copy(&element->prev_damage, damage);
466 element->need_swap = 1;
472 rpi_element_compute_rects(struct rpi_element *element,
473 VC_RECT_T *src_rect, VC_RECT_T *dst_rect)
475 struct weston_output *output = &element->output->base;
480 /* assume element->plane.{x,y} == element->surface->geometry.{x,y} */
483 width = element->surface->geometry.width;
484 height = element->surface->geometry.height;
486 dst_x = element->plane.x - output->x;
487 dst_y = element->plane.y - output->y;
501 width = int_max(width, 0);
502 height = int_max(height, 0);
504 /* src_rect is in 16.16, dst_rect is in 32.0 unsigned fixed point */
505 vc_dispmanx_rect_set(src_rect, src_x << 16, src_y << 16,
506 width << 16, height << 16);
507 vc_dispmanx_rect_set(dst_rect, dst_x, dst_y, width, height);
511 rpi_element_dmx_add(struct rpi_element *element,
512 DISPMANX_UPDATE_HANDLE_T update, int layer)
514 VC_DISPMANX_ALPHA_T alphasetup = {
515 DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_PREMULT,
516 255, /* opacity 0-255 */
517 0 /* mask resource handle */
522 rpi_element_compute_rects(element, &src_rect, &dst_rect);
524 element->handle = vc_dispmanx_element_add(
526 element->output->display,
529 element->back->handle,
531 DISPMANX_PROTECTION_NONE,
535 DBG("element %p add %u\n", element, element->handle);
539 rpi_element_dmx_swap(struct rpi_element *element,
540 DISPMANX_UPDATE_HANDLE_T update)
545 /* XXX: skip, iff resource was not reallocated, and single-buffering */
546 vc_dispmanx_element_change_source(update, element->handle,
547 element->back->handle);
549 /* This is current damage now, after rpi_assign_plane() */
550 r = pixman_region32_extents(&element->prev_damage);
552 vc_dispmanx_rect_set(&rect, r->x1, r->y1,
553 r->x2 - r->x1, r->y2 - r->y1);
554 vc_dispmanx_element_modified(update, element->handle, &rect);
555 DBG("element %p swap\n", element);
559 rpi_element_dmx_move(struct rpi_element *element,
560 DISPMANX_UPDATE_HANDLE_T update, int layer)
565 /* XXX: return early, if all attributes stay the same */
567 rpi_element_compute_rects(element, &src_rect, &dst_rect);
569 vc_dispmanx_element_change_attributes(
572 ELEMENT_CHANGE_LAYER |
573 ELEMENT_CHANGE_DEST_RECT |
574 ELEMENT_CHANGE_SRC_RECT,
581 DBG("element %p move\n", element);
585 rpi_element_update(struct rpi_element *element,
586 DISPMANX_UPDATE_HANDLE_T update, int layer)
588 struct rpi_resource *tmp;
590 if (element->handle == DISPMANX_NO_HANDLE) {
591 /* need_swap is already true, see rpi_assign_plane() */
593 rpi_element_dmx_add(element, update, layer);
594 if (element->handle == DISPMANX_NO_HANDLE)
595 weston_log("ERROR rpi: element_add() failed.\n");
597 if (element->need_swap)
598 rpi_element_dmx_swap(element, update);
599 rpi_element_dmx_move(element, update, layer);
601 element->layer = layer;
603 if (element->need_swap) {
604 tmp = element->front;
605 element->front = element->back;
607 element->need_swap = 0;
608 DBG("new back %p, new front %p\n",
609 element->back, element->front);
616 rpi_get_current_time(void)
620 /* XXX: use CLOCK_MONOTONIC instead? */
621 gettimeofday(&tv, NULL);
622 return (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
626 rpi_flippipe_update_complete(DISPMANX_UPDATE_HANDLE_T update, void *data)
628 /* This function runs in a different thread. */
629 struct rpi_flippipe *flippipe = data;
633 /* manufacture flip completion timestamp */
634 time = rpi_get_current_time();
636 ret = write(flippipe->writefd, &time, sizeof time);
637 if (ret != sizeof time)
638 weston_log("ERROR: %s failed to write, ret %zd, errno %d\n",
639 __func__, ret, errno);
643 rpi_dispmanx_update_submit(DISPMANX_UPDATE_HANDLE_T update,
644 struct rpi_output *output)
647 * The callback registered here will eventually be called
648 * in a different thread context. Therefore we cannot call
649 * the usual functions from rpi_flippipe_update_complete().
650 * Instead, we have a pipe for passing the message from the
651 * thread, waking up the Weston main event loop, calling
652 * rpi_flippipe_handler(), and then ending up in
653 * rpi_output_update_complete() in the main thread context,
654 * where we can do the frame finishing work.
656 return vc_dispmanx_update_submit(update, rpi_flippipe_update_complete,
661 rpi_output_update_complete(struct rpi_output *output, uint64_t time);
664 rpi_flippipe_handler(int fd, uint32_t mask, void *data)
666 struct rpi_output *output = data;
670 if (mask != WL_EVENT_READABLE)
671 weston_log("ERROR: unexpected mask 0x%x in %s\n",
674 ret = read(fd, &time, sizeof time);
675 if (ret != sizeof time) {
676 weston_log("ERROR: %s failed to read, ret %zd, errno %d\n",
677 __func__, ret, errno);
680 rpi_output_update_complete(output, time);
686 rpi_flippipe_init(struct rpi_flippipe *flippipe, struct rpi_output *output)
688 struct wl_event_loop *loop;
691 if (pipe2(fd, O_CLOEXEC) == -1)
694 flippipe->readfd = fd[0];
695 flippipe->writefd = fd[1];
697 loop = wl_display_get_event_loop(output->compositor->base.wl_display);
698 flippipe->source = wl_event_loop_add_fd(loop, flippipe->readfd,
700 rpi_flippipe_handler, output);
702 if (!flippipe->source) {
703 close(flippipe->readfd);
704 close(flippipe->writefd);
712 rpi_flippipe_release(struct rpi_flippipe *flippipe)
714 wl_event_source_remove(flippipe->source);
715 close(flippipe->readfd);
716 close(flippipe->writefd);
719 static struct rpi_element *
720 find_rpi_element_from_surface(struct weston_surface *surface)
722 struct wl_listener *listener;
723 struct rpi_element *element;
725 listener = wl_signal_get(&surface->surface.resource.destroy_signal,
726 rpi_element_handle_surface_destroy);
730 element = container_of(listener, struct rpi_element,
731 surface_destroy_listener);
733 if (element->surface != surface)
734 weston_log("ERROR rpi: sanity check failure in %s.\n",
740 static struct rpi_element *
741 rpi_assign_plane(struct weston_surface *surface, struct rpi_output *output)
743 struct rpi_element *element;
745 /* dispmanx elements cannot transform */
746 if (surface->transform.enabled) {
747 /* XXX: inspect the transformation matrix, we might still
748 * be able to put it into an element; scaling, additional
749 * translation (window titlebar context menus?)
751 DBG("surface %p rejected: transform\n", surface);
755 /* only shm surfaces supported */
756 if (surface->buffer_ref.buffer &&
757 !wl_buffer_is_shm(surface->buffer_ref.buffer)) {
758 DBG("surface %p rejected: not shm\n", surface);
762 if (surface->buffer_transform != WL_OUTPUT_TRANSFORM_NORMAL) {
763 DBG("surface %p rejected: unsupported buffer transform\n",
768 /* check if this surface previously belonged to an element */
769 element = find_rpi_element_from_surface(surface);
772 rpi_element_reuse(element);
773 element->plane.x = floor(surface->geometry.x);
774 element->plane.y = floor(surface->geometry.y);
775 DBG("surface %p reuse element %p\n", surface, element);
777 if (!surface->buffer_ref.buffer) {
778 DBG("surface %p rejected: no buffer\n", surface);
782 element = rpi_element_create(output, surface);
783 DBG("element %p created\n", element);
787 DBG("surface %p rejected: no element\n", surface);
795 rpi_output_assign_planes(struct weston_output *base)
797 struct rpi_output *output = to_rpi_output(base);
798 struct rpi_compositor *compositor = output->compositor;
799 struct weston_surface *surface;
800 pixman_region32_t overlap;
801 pixman_region32_t surface_overlap;
802 struct rpi_element *element;
805 /* Construct the list of rpi_elements to be used into
806 * output->element_list, which is empty right now.
807 * Re-used elements are moved from old_element_list to
810 DBG("%s\n", __func__);
812 pixman_region32_init(&overlap);
813 wl_list_for_each(surface, &compositor->base.surface_list, link) {
814 /* always, since all buffers are shm on rpi */
815 surface->keep_buffer = 1;
817 pixman_region32_init(&surface_overlap);
818 pixman_region32_intersect(&surface_overlap, &overlap,
819 &surface->transform.boundingbox);
822 if (!pixman_region32_not_empty(&surface_overlap) &&
823 n < compositor->max_planes)
824 element = rpi_assign_plane(surface, output);
827 weston_surface_move_to_plane(surface, &element->plane);
828 DBG("surface %p (%dx%d@%.1f,%.1f) to element %p\n",
830 surface->geometry.width, surface->geometry.height,
831 surface->geometry.x, surface->geometry.y, element);
833 /* weston_surface_move_to_plane() does full-surface
834 * damage, if the plane is new, so no need to force
835 * initial resource update.
837 if (rpi_element_damage(element,
838 surface->buffer_ref.buffer,
839 &surface->damage) < 0) {
840 rpi_element_schedule_destroy(element);
841 DBG("surface %p rejected: resource update failed\n",
850 weston_surface_move_to_plane(surface,
851 &compositor->base.primary_plane);
852 DBG("surface %p (%dx%d@%.1f,%.1f) to primary plane\n",
854 surface->geometry.width, surface->geometry.height,
855 surface->geometry.x, surface->geometry.y);
856 pixman_region32_union(&overlap, &overlap,
857 &surface->transform.boundingbox);
860 pixman_region32_fini(&surface_overlap);
862 pixman_region32_fini(&overlap);
866 rpi_remove_elements(struct wl_list *element_list,
867 DISPMANX_UPDATE_HANDLE_T update)
869 struct rpi_element *element;
871 wl_list_for_each(element, element_list, link) {
872 if (element->handle == DISPMANX_NO_HANDLE)
875 vc_dispmanx_element_remove(update, element->handle);
876 DBG("element %p remove %u\n", element, element->handle);
877 element->handle = DISPMANX_NO_HANDLE;
882 rpi_output_destroy_old_elements(struct rpi_output *output)
884 struct rpi_element *element, *tmp;
886 wl_list_for_each_safe(element, tmp, &output->old_element_list, link) {
887 if (element->handle != DISPMANX_NO_HANDLE)
890 rpi_element_destroy(element);
895 rpi_output_start_repaint_loop(struct weston_output *output)
899 time = rpi_get_current_time();
900 weston_output_finish_frame(output, time);
904 rpi_output_repaint(struct weston_output *base, pixman_region32_t *damage)
906 struct rpi_output *output = to_rpi_output(base);
907 struct rpi_compositor *compositor = output->compositor;
908 struct weston_plane *primary_plane = &compositor->base.primary_plane;
909 struct rpi_element *element;
910 DISPMANX_UPDATE_HANDLE_T update;
913 DBG("%s\n", __func__);
915 update = vc_dispmanx_update_start(0);
917 /* update all live elements */
918 wl_list_for_each(element, &output->element_list, link) {
919 if (rpi_element_update(element, update, layer--) < 0)
920 weston_log("ERROR rpi: element update failed.\n");
923 /* remove all unused elements */
924 rpi_remove_elements(&output->old_element_list, update);
926 /* schedule callback to rpi_output_update_complete() */
927 rpi_dispmanx_update_submit(update, output);
929 /* XXX: if there is anything to composite in GL,
930 * framerate seems to suffer */
931 /* XXX: optimise the renderer for the case of nothing to render */
932 /* XXX: if nothing to render, remove the element...
933 * but how, is destroying the EGLSurface a bad performance hit?
935 compositor->base.renderer->repaint_output(&output->base, damage);
937 pixman_region32_subtract(&primary_plane->damage,
938 &primary_plane->damage, damage);
940 /* Move the list of elements into the old_element_list. */
941 wl_list_insert_list(&output->old_element_list, &output->element_list);
942 wl_list_init(&output->element_list);
946 rpi_output_update_complete(struct rpi_output *output, uint64_t time)
948 rpi_output_destroy_old_elements(output);
949 weston_output_finish_frame(&output->base, time);
953 rpi_output_destroy(struct weston_output *base)
955 struct rpi_output *output = to_rpi_output(base);
956 DISPMANX_UPDATE_HANDLE_T update;
957 struct rpi_element *element, *tmp;
959 DBG("%s\n", __func__);
961 rpi_flippipe_release(&output->flippipe);
963 update = vc_dispmanx_update_start(0);
964 rpi_remove_elements(&output->element_list, update);
965 rpi_remove_elements(&output->old_element_list, update);
966 vc_dispmanx_element_remove(update, output->egl_element);
967 vc_dispmanx_update_submit_sync(update);
969 gl_renderer_output_destroy(base);
971 wl_list_for_each_safe(element, tmp, &output->element_list, link)
972 rpi_element_destroy(element);
974 wl_list_for_each_safe(element, tmp, &output->old_element_list, link)
975 rpi_element_destroy(element);
977 wl_list_remove(&output->base.link);
978 weston_output_destroy(&output->base);
980 vc_dispmanx_display_close(output->display);
986 rpi_output_create(struct rpi_compositor *compositor)
988 struct rpi_output *output;
989 DISPMANX_MODEINFO_T modeinfo;
990 DISPMANX_UPDATE_HANDLE_T update;
994 float mm_width, mm_height;
995 VC_DISPMANX_ALPHA_T alphasetup = {
996 DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
997 255, /* opacity 0-255 */
998 0 /* mask resource handle */
1001 output = calloc(1, sizeof *output);
1005 output->compositor = compositor;
1006 output->single_buffer = compositor->single_buffer;
1007 wl_list_init(&output->element_list);
1008 wl_list_init(&output->old_element_list);
1010 if (rpi_flippipe_init(&output->flippipe, output) < 0) {
1011 weston_log("Creating message pipe failed.\n");
1015 output->display = vc_dispmanx_display_open(DISPMANX_ID_HDMI);
1016 if (!output->display) {
1017 weston_log("Failed to open dispmanx HDMI display.\n");
1021 ret = vc_dispmanx_display_get_info(output->display, &modeinfo);
1023 weston_log("Failed to get display mode information.\n");
1027 vc_dispmanx_rect_set(&dst_rect, 0, 0, modeinfo.width, modeinfo.height);
1028 vc_dispmanx_rect_set(&src_rect, 0, 0,
1029 modeinfo.width << 16, modeinfo.height << 16);
1031 update = vc_dispmanx_update_start(0);
1032 output->egl_element = vc_dispmanx_element_add(update,
1036 0 /* src resource */,
1038 DISPMANX_PROTECTION_NONE,
1041 DISPMANX_NO_ROTATE);
1042 vc_dispmanx_update_submit_sync(update);
1044 output->egl_window.element = output->egl_element;
1045 output->egl_window.width = modeinfo.width;
1046 output->egl_window.height = modeinfo.height;
1048 output->base.start_repaint_loop = rpi_output_start_repaint_loop;
1049 output->base.repaint = rpi_output_repaint;
1050 output->base.destroy = rpi_output_destroy;
1051 if (compositor->max_planes > 0)
1052 output->base.assign_planes = rpi_output_assign_planes;
1053 output->base.set_backlight = NULL;
1054 output->base.set_dpms = NULL;
1055 output->base.switch_mode = NULL;
1057 /* XXX: use tvservice to get information from and control the
1058 * HDMI and SDTV outputs. See:
1059 * /opt/vc/include/interface/vmcs_host/vc_tvservice.h
1062 /* only one static mode in list */
1063 output->mode.flags =
1064 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1065 output->mode.width = modeinfo.width;
1066 output->mode.height = modeinfo.height;
1067 output->mode.refresh = 60000;
1068 wl_list_init(&output->base.mode_list);
1069 wl_list_insert(&output->base.mode_list, &output->mode.link);
1071 output->base.current = &output->mode;
1072 output->base.origin = &output->mode;
1073 output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
1074 output->base.make = "unknown";
1075 output->base.model = "unknown";
1078 mm_width = modeinfo.width * (25.4f / 96.0f);
1079 mm_height = modeinfo.height * (25.4f / 96.0f);
1081 weston_output_init(&output->base, &compositor->base,
1082 0, 0, round(mm_width), round(mm_height),
1083 WL_OUTPUT_TRANSFORM_NORMAL);
1085 if (gl_renderer_output_create(&output->base,
1086 (EGLNativeWindowType)&output->egl_window) < 0)
1089 if (!eglSurfaceAttrib(gl_renderer_display(&compositor->base),
1090 gl_renderer_output_surface(&output->base),
1091 EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED)) {
1092 weston_log("Failed to set swap behaviour to preserved.\n");
1093 gl_renderer_print_egl_error_state();
1097 wl_list_insert(compositor->base.output_list.prev, &output->base.link);
1099 weston_log("Raspberry Pi HDMI output %dx%d px\n",
1100 output->mode.width, output->mode.height);
1101 weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
1102 output->mode.refresh / 1000);
1107 gl_renderer_output_destroy(&output->base);
1109 weston_output_destroy(&output->base);
1110 update = vc_dispmanx_update_start(0);
1111 vc_dispmanx_element_remove(update, output->egl_element);
1112 vc_dispmanx_update_submit_sync(update);
1115 vc_dispmanx_display_close(output->display);
1118 rpi_flippipe_release(&output->flippipe);
1126 rpi_led_update(struct weston_seat *seat_base, enum weston_led leds)
1128 struct rpi_seat *seat = to_rpi_seat(seat_base);
1129 struct evdev_device *device;
1131 wl_list_for_each(device, &seat->devices_list, link)
1132 evdev_led_update(device, leds);
1135 static const char default_seat[] = "seat0";
1138 device_added(struct udev_device *udev_device, struct rpi_seat *master)
1140 struct evdev_device *device;
1141 const char *devnode;
1142 const char *device_seat;
1145 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1147 device_seat = default_seat;
1149 if (strcmp(device_seat, master->seat_id))
1152 devnode = udev_device_get_devnode(udev_device);
1154 /* Use non-blocking mode so that we can loop on read on
1155 * evdev_device_data() until all events on the fd are
1156 * read. mtdev_get() also expects this. */
1157 fd = open(devnode, O_RDWR | O_NONBLOCK | O_CLOEXEC);
1159 weston_log("opening input device '%s' failed.\n", devnode);
1163 device = evdev_device_create(&master->base, devnode, fd);
1166 weston_log("not using input device '%s'.\n", devnode);
1170 wl_list_insert(master->devices_list.prev, &device->link);
1174 evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1176 struct rpi_seat *seat = to_rpi_seat(seat_base);
1177 struct udev_enumerate *e;
1178 struct udev_list_entry *entry;
1179 struct udev_device *device;
1180 const char *path, *sysname;
1182 e = udev_enumerate_new(udev);
1183 udev_enumerate_add_match_subsystem(e, "input");
1184 udev_enumerate_scan_devices(e);
1185 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1186 path = udev_list_entry_get_name(entry);
1187 device = udev_device_new_from_syspath(udev, path);
1189 sysname = udev_device_get_sysname(device);
1190 if (strncmp("event", sysname, 5) != 0) {
1191 udev_device_unref(device);
1195 device_added(device, seat);
1197 udev_device_unref(device);
1199 udev_enumerate_unref(e);
1201 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1203 if (wl_list_empty(&seat->devices_list)) {
1205 "warning: no input devices on entering Weston. "
1206 "Possible causes:\n"
1207 "\t- no permissions to read /dev/input/event*\n"
1208 "\t- seats misconfigured "
1209 "(Weston backend option 'seat', "
1210 "udev device property ID_SEAT)\n");
1215 evdev_udev_handler(int fd, uint32_t mask, void *data)
1217 struct rpi_seat *seat = data;
1218 struct udev_device *udev_device;
1219 struct evdev_device *device, *next;
1221 const char *devnode;
1223 udev_device = udev_monitor_receive_device(seat->udev_monitor);
1227 action = udev_device_get_action(udev_device);
1231 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1234 if (!strcmp(action, "add")) {
1235 device_added(udev_device, seat);
1237 else if (!strcmp(action, "remove")) {
1238 devnode = udev_device_get_devnode(udev_device);
1239 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1240 if (!strcmp(device->devnode, devnode)) {
1241 weston_log("input device %s, %s removed\n",
1242 device->devname, device->devnode);
1243 evdev_device_destroy(device);
1249 udev_device_unref(udev_device);
1255 evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1257 struct rpi_seat *master = to_rpi_seat(seat_base);
1258 struct wl_event_loop *loop;
1259 struct weston_compositor *c = master->base.compositor;
1262 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1263 if (!master->udev_monitor) {
1264 weston_log("udev: failed to create the udev monitor\n");
1268 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1271 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1272 weston_log("udev: failed to bind the udev monitor\n");
1273 udev_monitor_unref(master->udev_monitor);
1277 loop = wl_display_get_event_loop(c->wl_display);
1278 fd = udev_monitor_get_fd(master->udev_monitor);
1279 master->udev_monitor_source =
1280 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1281 evdev_udev_handler, master);
1282 if (!master->udev_monitor_source) {
1283 udev_monitor_unref(master->udev_monitor);
1291 evdev_disable_udev_monitor(struct weston_seat *seat_base)
1293 struct rpi_seat *seat = to_rpi_seat(seat_base);
1295 if (!seat->udev_monitor)
1298 udev_monitor_unref(seat->udev_monitor);
1299 seat->udev_monitor = NULL;
1300 wl_event_source_remove(seat->udev_monitor_source);
1301 seat->udev_monitor_source = NULL;
1305 evdev_input_create(struct weston_compositor *c, struct udev *udev,
1306 const char *seat_id)
1308 struct rpi_seat *seat;
1310 seat = malloc(sizeof *seat);
1314 memset(seat, 0, sizeof *seat);
1315 weston_seat_init(&seat->base, c);
1316 seat->base.led_update = rpi_led_update;
1318 wl_list_init(&seat->devices_list);
1319 seat->seat_id = strdup(seat_id);
1320 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1321 free(seat->seat_id);
1326 evdev_add_devices(udev, &seat->base);
1330 evdev_remove_devices(struct weston_seat *seat_base)
1332 struct rpi_seat *seat = to_rpi_seat(seat_base);
1333 struct evdev_device *device, *next;
1335 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1336 evdev_device_destroy(device);
1338 if (seat->base.seat.keyboard)
1339 notify_keyboard_focus_out(&seat->base);
1343 evdev_input_destroy(struct weston_seat *seat_base)
1345 struct rpi_seat *seat = to_rpi_seat(seat_base);
1347 evdev_remove_devices(seat_base);
1348 evdev_disable_udev_monitor(&seat->base);
1350 weston_seat_release(seat_base);
1351 free(seat->seat_id);
1356 rpi_compositor_destroy(struct weston_compositor *base)
1358 struct rpi_compositor *compositor = to_rpi_compositor(base);
1359 struct weston_seat *seat, *next;
1361 wl_list_for_each_safe(seat, next, &compositor->base.seat_list, link)
1362 evdev_input_destroy(seat);
1364 /* destroys outputs, too */
1365 weston_compositor_shutdown(&compositor->base);
1367 compositor->base.renderer->destroy(&compositor->base);
1368 tty_destroy(compositor->tty);
1375 vt_func(struct weston_compositor *base, int event)
1377 struct rpi_compositor *compositor = to_rpi_compositor(base);
1378 struct weston_seat *seat;
1379 struct weston_output *output;
1383 weston_log("entering VT\n");
1384 compositor->base.focus = 1;
1385 compositor->base.state = compositor->prev_state;
1386 weston_compositor_damage_all(&compositor->base);
1387 wl_list_for_each(seat, &compositor->base.seat_list, link) {
1388 evdev_add_devices(compositor->udev, seat);
1389 evdev_enable_udev_monitor(compositor->udev, seat);
1393 weston_log("leaving VT\n");
1394 wl_list_for_each(seat, &compositor->base.seat_list, link) {
1395 evdev_disable_udev_monitor(seat);
1396 evdev_remove_devices(seat);
1399 compositor->base.focus = 0;
1400 compositor->prev_state = compositor->base.state;
1401 weston_compositor_offscreen(&compositor->base);
1403 /* If we have a repaint scheduled (either from a
1404 * pending pageflip or the idle handler), make sure we
1405 * cancel that so we don't try to pageflip when we're
1406 * vt switched away. The OFFSCREEN state will prevent
1407 * further attemps at repainting. When we switch
1408 * back, we schedule a repaint, which will process
1409 * pending frame callbacks. */
1411 wl_list_for_each(output,
1412 &compositor->base.output_list, link) {
1413 output->repaint_needed = 0;
1421 rpi_restore(struct weston_compositor *base)
1423 struct rpi_compositor *compositor = to_rpi_compositor(base);
1425 tty_reset(compositor->tty);
1429 switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
1431 struct rpi_compositor *ec = data;
1433 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
1436 struct rpi_parameters {
1442 static struct weston_compositor *
1443 rpi_compositor_create(struct wl_display *display, int *argc, char *argv[],
1444 const char *config_file, struct rpi_parameters *param)
1446 struct rpi_compositor *compositor;
1447 const char *seat = default_seat;
1449 static const EGLint config_attrs[] = {
1450 EGL_SURFACE_TYPE, EGL_WINDOW_BIT |
1451 EGL_SWAP_BEHAVIOR_PRESERVED_BIT,
1456 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1460 weston_log("initializing Raspberry Pi backend\n");
1462 compositor = calloc(1, sizeof *compositor);
1463 if (compositor == NULL)
1466 if (weston_compositor_init(&compositor->base, display, argc, argv,
1470 compositor->udev = udev_new();
1471 if (compositor->udev == NULL) {
1472 weston_log("Failed to initialize udev context.\n");
1473 goto out_compositor;
1476 compositor->tty = tty_create(&compositor->base, vt_func, param->tty);
1477 if (!compositor->tty) {
1478 weston_log("Failed to initialize tty.\n");
1482 compositor->base.destroy = rpi_compositor_destroy;
1483 compositor->base.restore = rpi_restore;
1485 compositor->base.focus = 1;
1486 compositor->prev_state = WESTON_COMPOSITOR_ACTIVE;
1487 compositor->max_planes = int_max(param->max_planes, 0);
1488 compositor->single_buffer = param->single_buffer;
1490 weston_log("Maximum number of additional Dispmanx planes: %d\n",
1491 compositor->max_planes);
1492 weston_log("Dispmanx planes are %s buffered.\n",
1493 compositor->single_buffer ? "single" : "double");
1495 for (key = KEY_F1; key < KEY_F9; key++)
1496 weston_compositor_add_key_binding(&compositor->base, key,
1497 MODIFIER_CTRL | MODIFIER_ALT,
1498 switch_vt_binding, compositor);
1501 * bcm_host_init() creates threads.
1502 * Therefore we must have all signal handlers set and signals blocked
1503 * before calling it. Otherwise the signals may end in the bcm
1504 * threads and cause the default behaviour there. For instance,
1505 * SIGUSR1 used for VT switching caused Weston to terminate there.
1509 if (gl_renderer_create(&compositor->base, EGL_DEFAULT_DISPLAY,
1510 config_attrs, NULL) < 0)
1513 if (rpi_output_create(compositor) < 0)
1516 evdev_input_create(&compositor->base, compositor->udev, seat);
1518 return &compositor->base;
1521 compositor->base.renderer->destroy(&compositor->base);
1524 tty_destroy(compositor->tty);
1527 udev_unref(compositor->udev);
1530 weston_compositor_shutdown(&compositor->base);
1540 * If you have a recent enough firmware in Raspberry Pi, that
1541 * supports falling back to off-line hardware compositing, and
1542 * you have enabled it with dispmanx_offline=1 in /boot/config.txt,
1543 * then VideoCore should be able to handle almost 100 Dispmanx
1544 * elements. Therefore use 80 as the default limit.
1546 * If you don't have off-line compositing support, this would be
1547 * better as something like 10. Failing on-line compositing may
1548 * show up as visible glitches, HDMI blanking, or invisible surfaces.
1550 * When the max-planes number is reached, rpi-backend will start
1551 * to fall back to GLESv2 compositing.
1553 #define DEFAULT_MAX_PLANES 80
1555 WL_EXPORT struct weston_compositor *
1556 backend_init(struct wl_display *display, int *argc, char *argv[],
1557 const char *config_file)
1559 struct rpi_parameters param = {
1560 .tty = 0, /* default to current tty */
1561 .max_planes = DEFAULT_MAX_PLANES,
1565 const struct weston_option rpi_options[] = {
1566 { WESTON_OPTION_INTEGER, "tty", 0, ¶m.tty },
1567 { WESTON_OPTION_INTEGER, "max-planes", 0, ¶m.max_planes },
1568 { WESTON_OPTION_BOOLEAN, "single-buffer", 0,
1569 ¶m.single_buffer },
1572 parse_options(rpi_options, ARRAY_LENGTH(rpi_options), argc, argv);
1574 return rpi_compositor_create(display, argc, argv, config_file, ¶m);