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.
32 #include <sys/types.h>
41 # include <bcm_host.h>
43 # include "rpi-bcm-stubs.h"
46 #include "compositor.h"
47 #include "rpi-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;
152 struct wl_list element_list; /* struct rpi_element */
153 struct wl_list old_element_list; /* struct rpi_element */
157 struct weston_seat base;
158 struct wl_list devices_list;
160 struct udev_monitor *udev_monitor;
161 struct wl_event_source *udev_monitor_source;
165 struct rpi_compositor {
166 struct weston_compositor base;
172 int max_planes; /* per output, really */
176 static inline struct rpi_output *
177 to_rpi_output(struct weston_output *base)
179 return container_of(base, struct rpi_output, base);
182 static inline struct rpi_seat *
183 to_rpi_seat(struct weston_seat *base)
185 return container_of(base, struct rpi_seat, base);
188 static inline struct rpi_compositor *
189 to_rpi_compositor(struct weston_compositor *base)
191 return container_of(base, struct rpi_compositor, base);
195 int_max(int a, int b)
197 return a > b ? a : b;
201 rpi_resource_init(struct rpi_resource *resource)
203 resource->handle = DISPMANX_NO_HANDLE;
207 rpi_resource_release(struct rpi_resource *resource)
209 if (resource->handle == DISPMANX_NO_HANDLE)
212 vc_dispmanx_resource_delete(resource->handle);
213 DBG("resource %p release\n", resource);
214 resource->handle = DISPMANX_NO_HANDLE;
218 rpi_resource_realloc(struct rpi_resource *resource, VC_IMAGE_TYPE_T ifmt,
219 int width, int height, int stride, int buffer_height)
223 if (resource->handle != DISPMANX_NO_HANDLE &&
224 resource->width == width &&
225 resource->height == height &&
226 resource->stride == stride &&
227 resource->buffer_height == buffer_height &&
228 resource->ifmt == ifmt)
231 rpi_resource_release(resource);
233 /* NOTE: if stride is not a multiple of 16 pixels in bytes,
234 * the vc_image_* functions may break. Dispmanx elements
235 * should be fine, though. Buffer_height probably has similar
239 vc_dispmanx_resource_create(ifmt,
240 width | (stride << 16),
241 height | (buffer_height << 16),
243 if (resource->handle == DISPMANX_NO_HANDLE)
246 resource->width = width;
247 resource->height = height;
248 resource->stride = stride;
249 resource->buffer_height = buffer_height;
250 resource->ifmt = ifmt;
251 DBG("resource %p alloc\n", resource);
255 static VC_IMAGE_TYPE_T
256 shm_buffer_get_vc_format(struct wl_buffer *buffer)
258 switch (wl_shm_buffer_get_format(buffer)) {
259 case WL_SHM_FORMAT_XRGB8888:
260 return VC_IMAGE_XRGB8888;
261 case WL_SHM_FORMAT_ARGB8888:
262 return VC_IMAGE_ARGB8888;
270 rpi_resource_update(struct rpi_resource *resource, struct wl_buffer *buffer,
271 pixman_region32_t *region)
273 pixman_region32_t write_region;
276 VC_IMAGE_TYPE_T ifmt;
282 #ifdef HAVE_RESOURCE_WRITE_DATA_RECT
289 ifmt = shm_buffer_get_vc_format(buffer);
290 width = wl_shm_buffer_get_width(buffer);
291 height = wl_shm_buffer_get_height(buffer);
292 stride = wl_shm_buffer_get_stride(buffer);
293 pixels = wl_shm_buffer_get_data(buffer);
295 if (rpi_resource_realloc(resource, ifmt, width, height,
299 pixman_region32_init(&write_region);
300 pixman_region32_intersect_rect(&write_region, region,
301 0, 0, width, height);
303 #ifdef HAVE_RESOURCE_WRITE_DATA_RECT
304 /* XXX: Can this do a format conversion, so that scanout does not have to? */
305 r = pixman_region32_rectangles(&write_region, &n);
307 vc_dispmanx_rect_set(&rect, r[n].x1, r[n].y1,
308 r[n].x2 - r[n].x1, r[n].y2 - r[n].y1);
310 ret = vc_dispmanx_resource_write_data_rect(resource->handle,
314 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
315 rect.width, rect.height, rect.x, rect.y, ret);
320 /* vc_dispmanx_resource_write_data() ignores ifmt,
321 * rect.x, rect.width, and uses stride only for computing
322 * the size of the transfer as rect.height * stride.
323 * Therefore we can only write rows starting at x=0.
324 * To be able to write more than one scanline at a time,
325 * the resource must have been created with the same stride
326 * as used here, and we must write full scanlines.
329 r = pixman_region32_extents(&write_region);
330 vc_dispmanx_rect_set(&rect, 0, r->y1, width, r->y2 - r->y1);
331 ret = vc_dispmanx_resource_write_data(resource->handle, ifmt,
332 stride, pixels, &rect);
333 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
334 width, r->y2 - r->y1, 0, r->y1, ret);
337 pixman_region32_fini(&write_region);
343 rpi_element_handle_surface_destroy(struct wl_listener *listener, void *data)
345 struct rpi_element *element =
346 container_of(listener, struct rpi_element,
347 surface_destroy_listener);
349 element->surface = NULL;
352 static struct rpi_element *
353 rpi_element_create(struct rpi_output *output, struct weston_surface *surface)
355 struct rpi_element *element;
357 element = calloc(1, sizeof *element);
361 element->output = output;
362 element->single_buffer = output->single_buffer;
363 element->handle = DISPMANX_NO_HANDLE;
364 rpi_resource_init(&element->resources[0]);
365 rpi_resource_init(&element->resources[1]);
366 element->front = &element->resources[0];
368 if (element->single_buffer) {
369 element->back = element->front;
371 element->back = &element->resources[1];
374 pixman_region32_init(&element->prev_damage);
376 weston_plane_init(&element->plane, floor(surface->geometry.x),
377 floor(surface->geometry.y));
379 element->surface = surface;
380 element->surface_destroy_listener.notify =
381 rpi_element_handle_surface_destroy;
382 wl_signal_add(&surface->resource.destroy_signal,
383 &element->surface_destroy_listener);
385 wl_list_insert(output->element_list.prev, &element->link);
391 rpi_element_destroy(struct rpi_element *element)
393 struct weston_surface *surface = element->surface;
396 if (surface->plane == &element->plane) {
397 /* If a surface, that was on a plane, gets hidden,
398 * it will not appear in the repaint surface list,
399 * is never considered in rpi_output_assign_planes(),
400 * and hence can stay assigned to this element's plane.
401 * We need to reassign it here.
403 DBG("surface %p (%dx%d@%.1f,%.1f) to primary plane*\n",
405 surface->geometry.width, surface->geometry.height,
406 surface->geometry.x, surface->geometry.y);
407 weston_surface_move_to_plane(surface,
408 &surface->compositor->primary_plane);
410 wl_list_remove(&element->surface_destroy_listener.link);
413 wl_list_remove(&element->link);
414 weston_plane_release(&element->plane);
416 if (element->handle != DISPMANX_NO_HANDLE)
417 weston_log("ERROR rpi: destroying on-screen element\n");
419 pixman_region32_fini(&element->prev_damage);
420 rpi_resource_release(&element->resources[0]);
421 rpi_resource_release(&element->resources[1]);
422 DBG("element %p destroyed (%u)\n", element, element->handle);
428 rpi_element_reuse(struct rpi_element *element)
430 wl_list_remove(&element->link);
431 wl_list_insert(element->output->element_list.prev, &element->link);
435 rpi_element_schedule_destroy(struct rpi_element *element)
437 wl_list_remove(&element->link);
438 wl_list_insert(element->output->old_element_list.prev,
443 rpi_element_damage(struct rpi_element *element, struct wl_buffer *buffer,
444 pixman_region32_t *damage)
446 pixman_region32_t upload;
449 if (!pixman_region32_not_empty(damage))
452 DBG("element %p update resource %p\n", element, element->back);
454 if (element->single_buffer) {
455 ret = rpi_resource_update(element->back, buffer, damage);
457 pixman_region32_init(&upload);
458 pixman_region32_union(&upload, &element->prev_damage, damage);
459 ret = rpi_resource_update(element->back, buffer, &upload);
460 pixman_region32_fini(&upload);
463 pixman_region32_copy(&element->prev_damage, damage);
464 element->need_swap = 1;
470 rpi_element_compute_rects(struct rpi_element *element,
471 VC_RECT_T *src_rect, VC_RECT_T *dst_rect)
473 struct weston_output *output = &element->output->base;
478 /* assume element->plane.{x,y} == element->surface->geometry.{x,y} */
481 width = element->surface->geometry.width;
482 height = element->surface->geometry.height;
484 dst_x = element->plane.x - output->x;
485 dst_y = element->plane.y - output->y;
499 width = int_max(width, 0);
500 height = int_max(height, 0);
502 /* src_rect is in 16.16, dst_rect is in 32.0 unsigned fixed point */
503 vc_dispmanx_rect_set(src_rect, src_x << 16, src_y << 16,
504 width << 16, height << 16);
505 vc_dispmanx_rect_set(dst_rect, dst_x, dst_y, width, height);
509 rpi_element_dmx_add(struct rpi_element *element,
510 DISPMANX_UPDATE_HANDLE_T update, int layer)
512 VC_DISPMANX_ALPHA_T alphasetup = {
513 DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_PREMULT,
514 255, /* opacity 0-255 */
515 0 /* mask resource handle */
520 rpi_element_compute_rects(element, &src_rect, &dst_rect);
522 element->handle = vc_dispmanx_element_add(
524 element->output->display,
527 element->back->handle,
529 DISPMANX_PROTECTION_NONE,
533 DBG("element %p add %u\n", element, element->handle);
537 rpi_element_dmx_swap(struct rpi_element *element,
538 DISPMANX_UPDATE_HANDLE_T update)
543 /* XXX: skip, iff resource was not reallocated, and single-buffering */
544 vc_dispmanx_element_change_source(update, element->handle,
545 element->back->handle);
547 /* This is current damage now, after rpi_assign_plane() */
548 r = pixman_region32_extents(&element->prev_damage);
550 vc_dispmanx_rect_set(&rect, r->x1, r->y1,
551 r->x2 - r->x1, r->y2 - r->y1);
552 vc_dispmanx_element_modified(update, element->handle, &rect);
553 DBG("element %p swap\n", element);
557 rpi_element_dmx_move(struct rpi_element *element,
558 DISPMANX_UPDATE_HANDLE_T update, int layer)
563 /* XXX: return early, if all attributes stay the same */
565 rpi_element_compute_rects(element, &src_rect, &dst_rect);
567 vc_dispmanx_element_change_attributes(
570 ELEMENT_CHANGE_LAYER |
571 ELEMENT_CHANGE_DEST_RECT |
572 ELEMENT_CHANGE_SRC_RECT,
579 DBG("element %p move\n", element);
583 rpi_element_update(struct rpi_element *element,
584 DISPMANX_UPDATE_HANDLE_T update, int layer)
586 struct rpi_resource *tmp;
588 if (element->handle == DISPMANX_NO_HANDLE) {
589 /* need_swap is already true, see rpi_assign_plane() */
591 rpi_element_dmx_add(element, update, layer);
592 if (element->handle == DISPMANX_NO_HANDLE)
593 weston_log("ERROR rpi: element_add() failed.\n");
595 if (element->need_swap)
596 rpi_element_dmx_swap(element, update);
597 rpi_element_dmx_move(element, update, layer);
599 element->layer = layer;
601 if (element->need_swap) {
602 tmp = element->front;
603 element->front = element->back;
605 element->need_swap = 0;
606 DBG("new back %p, new front %p\n",
607 element->back, element->front);
614 rpi_get_current_time(void)
618 /* XXX: use CLOCK_MONOTONIC instead? */
619 gettimeofday(&tv, NULL);
620 return (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
624 rpi_flippipe_update_complete(DISPMANX_UPDATE_HANDLE_T update, void *data)
626 /* This function runs in a different thread. */
627 struct rpi_flippipe *flippipe = data;
631 /* manufacture flip completion timestamp */
632 time = rpi_get_current_time();
634 ret = write(flippipe->writefd, &time, sizeof time);
635 if (ret != sizeof time)
636 weston_log("ERROR: %s failed to write, ret %zd, errno %d\n",
637 __func__, ret, errno);
641 rpi_dispmanx_update_submit(DISPMANX_UPDATE_HANDLE_T update,
642 struct rpi_output *output)
645 * The callback registered here will eventually be called
646 * in a different thread context. Therefore we cannot call
647 * the usual functions from rpi_flippipe_update_complete().
648 * Instead, we have a pipe for passing the message from the
649 * thread, waking up the Weston main event loop, calling
650 * rpi_flippipe_handler(), and then ending up in
651 * rpi_output_update_complete() in the main thread context,
652 * where we can do the frame finishing work.
654 return vc_dispmanx_update_submit(update, rpi_flippipe_update_complete,
659 rpi_output_update_complete(struct rpi_output *output, uint64_t time);
662 rpi_flippipe_handler(int fd, uint32_t mask, void *data)
664 struct rpi_output *output = data;
668 if (mask != WL_EVENT_READABLE)
669 weston_log("ERROR: unexpected mask 0x%x in %s\n",
672 ret = read(fd, &time, sizeof time);
673 if (ret != sizeof time) {
674 weston_log("ERROR: %s failed to read, ret %zd, errno %d\n",
675 __func__, ret, errno);
678 rpi_output_update_complete(output, time);
684 rpi_flippipe_init(struct rpi_flippipe *flippipe, struct rpi_output *output)
686 struct wl_event_loop *loop;
689 if (pipe2(fd, O_CLOEXEC) == -1)
692 flippipe->readfd = fd[0];
693 flippipe->writefd = fd[1];
695 loop = wl_display_get_event_loop(output->compositor->base.wl_display);
696 flippipe->source = wl_event_loop_add_fd(loop, flippipe->readfd,
698 rpi_flippipe_handler, output);
700 if (!flippipe->source) {
701 close(flippipe->readfd);
702 close(flippipe->writefd);
710 rpi_flippipe_release(struct rpi_flippipe *flippipe)
712 wl_event_source_remove(flippipe->source);
713 close(flippipe->readfd);
714 close(flippipe->writefd);
717 static struct rpi_element *
718 find_rpi_element_from_surface(struct weston_surface *surface)
720 struct wl_listener *listener;
721 struct rpi_element *element;
723 listener = wl_signal_get(&surface->resource.destroy_signal,
724 rpi_element_handle_surface_destroy);
728 element = container_of(listener, struct rpi_element,
729 surface_destroy_listener);
731 if (element->surface != surface)
732 weston_log("ERROR rpi: sanity check failure in %s.\n",
738 static struct rpi_element *
739 rpi_assign_plane(struct weston_surface *surface, struct rpi_output *output)
741 struct rpi_element *element;
743 /* dispmanx elements cannot transform */
744 if (surface->transform.enabled) {
745 /* XXX: inspect the transformation matrix, we might still
746 * be able to put it into an element; scaling, additional
747 * translation (window titlebar context menus?)
749 DBG("surface %p rejected: transform\n", surface);
753 /* only shm surfaces supported */
754 if (surface->buffer_ref.buffer &&
755 !wl_buffer_is_shm(surface->buffer_ref.buffer)) {
756 DBG("surface %p rejected: not shm\n", surface);
760 if (surface->buffer_transform != WL_OUTPUT_TRANSFORM_NORMAL) {
761 DBG("surface %p rejected: unsupported buffer transform\n",
766 /* check if this surface previously belonged to an element */
767 element = find_rpi_element_from_surface(surface);
770 rpi_element_reuse(element);
771 element->plane.x = floor(surface->geometry.x);
772 element->plane.y = floor(surface->geometry.y);
773 DBG("surface %p reuse element %p\n", surface, element);
775 if (!surface->buffer_ref.buffer) {
776 DBG("surface %p rejected: no buffer\n", surface);
780 element = rpi_element_create(output, surface);
781 DBG("element %p created\n", element);
785 DBG("surface %p rejected: no element\n", surface);
793 rpi_output_assign_planes(struct weston_output *base)
795 struct rpi_output *output = to_rpi_output(base);
796 struct rpi_compositor *compositor = output->compositor;
797 struct weston_surface *surface;
798 pixman_region32_t overlap;
799 pixman_region32_t surface_overlap;
800 struct rpi_element *element;
803 /* Construct the list of rpi_elements to be used into
804 * output->element_list, which is empty right now.
805 * Re-used elements are moved from old_element_list to
808 DBG("%s\n", __func__);
810 pixman_region32_init(&overlap);
811 wl_list_for_each(surface, &compositor->base.surface_list, link) {
812 /* always, since all buffers are shm on rpi */
813 surface->keep_buffer = 1;
815 pixman_region32_init(&surface_overlap);
816 pixman_region32_intersect(&surface_overlap, &overlap,
817 &surface->transform.boundingbox);
820 if (!pixman_region32_not_empty(&surface_overlap) &&
821 n < compositor->max_planes)
822 element = rpi_assign_plane(surface, output);
825 weston_surface_move_to_plane(surface, &element->plane);
826 DBG("surface %p (%dx%d@%.1f,%.1f) to element %p\n",
828 surface->geometry.width, surface->geometry.height,
829 surface->geometry.x, surface->geometry.y, element);
831 /* weston_surface_move_to_plane() does full-surface
832 * damage, if the plane is new, so no need to force
833 * initial resource update.
835 if (rpi_element_damage(element,
836 surface->buffer_ref.buffer,
837 &surface->damage) < 0) {
838 rpi_element_schedule_destroy(element);
839 DBG("surface %p rejected: resource update failed\n",
848 weston_surface_move_to_plane(surface,
849 &compositor->base.primary_plane);
850 DBG("surface %p (%dx%d@%.1f,%.1f) to primary plane\n",
852 surface->geometry.width, surface->geometry.height,
853 surface->geometry.x, surface->geometry.y);
854 pixman_region32_union(&overlap, &overlap,
855 &surface->transform.boundingbox);
858 pixman_region32_fini(&surface_overlap);
860 pixman_region32_fini(&overlap);
864 rpi_remove_elements(struct wl_list *element_list,
865 DISPMANX_UPDATE_HANDLE_T update)
867 struct rpi_element *element;
869 wl_list_for_each(element, element_list, link) {
870 if (element->handle == DISPMANX_NO_HANDLE)
873 vc_dispmanx_element_remove(update, element->handle);
874 DBG("element %p remove %u\n", element, element->handle);
875 element->handle = DISPMANX_NO_HANDLE;
880 rpi_output_destroy_old_elements(struct rpi_output *output)
882 struct rpi_element *element, *tmp;
884 wl_list_for_each_safe(element, tmp, &output->old_element_list, link) {
885 if (element->handle != DISPMANX_NO_HANDLE)
888 rpi_element_destroy(element);
893 rpi_output_start_repaint_loop(struct weston_output *output)
897 time = rpi_get_current_time();
898 weston_output_finish_frame(output, time);
902 rpi_output_repaint(struct weston_output *base, pixman_region32_t *damage)
904 struct rpi_output *output = to_rpi_output(base);
905 struct rpi_compositor *compositor = output->compositor;
906 struct weston_plane *primary_plane = &compositor->base.primary_plane;
907 struct rpi_element *element;
908 DISPMANX_UPDATE_HANDLE_T update;
911 DBG("frame update start\n");
913 /* Update priority higher than in rpi-renderer's
914 * output destroy function, see rpi_output_destroy().
916 update = vc_dispmanx_update_start(1);
918 /* update all live elements */
919 wl_list_for_each(element, &output->element_list, link) {
920 if (rpi_element_update(element, update, layer--) < 0)
921 weston_log("ERROR rpi: element update failed.\n");
924 /* remove all unused elements */
925 rpi_remove_elements(&output->old_element_list, update);
927 rpi_renderer_set_update_handle(&output->base, update);
928 compositor->base.renderer->repaint_output(&output->base, damage);
930 pixman_region32_subtract(&primary_plane->damage,
931 &primary_plane->damage, damage);
933 /* schedule callback to rpi_output_update_complete() */
934 rpi_dispmanx_update_submit(update, output);
935 DBG("frame update submitted\n");
937 /* Move the list of elements into the old_element_list. */
938 wl_list_insert_list(&output->old_element_list, &output->element_list);
939 wl_list_init(&output->element_list);
943 rpi_output_update_complete(struct rpi_output *output, uint64_t time)
945 DBG("frame update complete(%" PRIu64 ")\n", time);
946 rpi_output_destroy_old_elements(output);
947 rpi_renderer_finish_frame(&output->base);
948 weston_output_finish_frame(&output->base, time);
952 rpi_output_destroy(struct weston_output *base)
954 struct rpi_output *output = to_rpi_output(base);
955 DISPMANX_UPDATE_HANDLE_T update;
956 struct rpi_element *element, *tmp;
958 DBG("%s\n", __func__);
960 update = vc_dispmanx_update_start(0);
961 rpi_remove_elements(&output->element_list, update);
962 rpi_remove_elements(&output->old_element_list, update);
963 vc_dispmanx_update_submit_sync(update);
965 rpi_renderer_output_destroy(base);
967 wl_list_for_each_safe(element, tmp, &output->element_list, link)
968 rpi_element_destroy(element);
970 wl_list_for_each_safe(element, tmp, &output->old_element_list, link)
971 rpi_element_destroy(element);
973 /* rpi_renderer_output_destroy() will schedule a removal of
974 * all Dispmanx Elements, and wait for the update to complete.
975 * Assuming updates are sequential, the wait should guarantee,
976 * that any pending rpi_flippipe_update_complete() callbacks
977 * have happened already. Therefore we can destroy the flippipe
980 rpi_flippipe_release(&output->flippipe);
982 wl_list_remove(&output->base.link);
983 weston_output_destroy(&output->base);
985 vc_dispmanx_display_close(output->display);
990 static const char *transform_names[] = {
991 [WL_OUTPUT_TRANSFORM_NORMAL] = "normal",
992 [WL_OUTPUT_TRANSFORM_90] = "90",
993 [WL_OUTPUT_TRANSFORM_180] = "180",
994 [WL_OUTPUT_TRANSFORM_270] = "270",
995 [WL_OUTPUT_TRANSFORM_FLIPPED] = "flipped",
996 [WL_OUTPUT_TRANSFORM_FLIPPED_90] = "flipped-90",
997 [WL_OUTPUT_TRANSFORM_FLIPPED_180] = "flipped-180",
998 [WL_OUTPUT_TRANSFORM_FLIPPED_270] = "flipped-270",
1002 str2transform(const char *name)
1006 for (i = 0; i < ARRAY_LENGTH(transform_names); i++)
1007 if (strcmp(name, transform_names[i]) == 0)
1014 transform2str(uint32_t output_transform)
1016 if (output_transform >= ARRAY_LENGTH(transform_names))
1017 return "<illegal value>";
1019 return transform_names[output_transform];
1023 rpi_output_create(struct rpi_compositor *compositor, uint32_t transform)
1025 struct rpi_output *output;
1026 DISPMANX_MODEINFO_T modeinfo;
1028 float mm_width, mm_height;
1030 output = calloc(1, sizeof *output);
1034 output->compositor = compositor;
1035 output->single_buffer = compositor->single_buffer;
1036 wl_list_init(&output->element_list);
1037 wl_list_init(&output->old_element_list);
1039 if (rpi_flippipe_init(&output->flippipe, output) < 0) {
1040 weston_log("Creating message pipe failed.\n");
1044 output->display = vc_dispmanx_display_open(DISPMANX_ID_HDMI);
1045 if (!output->display) {
1046 weston_log("Failed to open dispmanx HDMI display.\n");
1050 ret = vc_dispmanx_display_get_info(output->display, &modeinfo);
1052 weston_log("Failed to get display mode information.\n");
1056 output->base.start_repaint_loop = rpi_output_start_repaint_loop;
1057 output->base.repaint = rpi_output_repaint;
1058 output->base.destroy = rpi_output_destroy;
1059 output->base.assign_planes = NULL;
1060 output->base.set_backlight = NULL;
1061 output->base.set_dpms = NULL;
1062 output->base.switch_mode = NULL;
1064 /* XXX: use tvservice to get information from and control the
1065 * HDMI and SDTV outputs. See:
1066 * /opt/vc/include/interface/vmcs_host/vc_tvservice.h
1069 /* only one static mode in list */
1070 output->mode.flags =
1071 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1072 output->mode.width = modeinfo.width;
1073 output->mode.height = modeinfo.height;
1074 output->mode.refresh = 60000;
1075 wl_list_init(&output->base.mode_list);
1076 wl_list_insert(&output->base.mode_list, &output->mode.link);
1078 output->base.current = &output->mode;
1079 output->base.origin = &output->mode;
1080 output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
1081 output->base.make = "unknown";
1082 output->base.model = "unknown";
1085 mm_width = modeinfo.width * (25.4f / 96.0f);
1086 mm_height = modeinfo.height * (25.4f / 96.0f);
1088 weston_output_init(&output->base, &compositor->base,
1089 0, 0, round(mm_width), round(mm_height),
1092 if (rpi_renderer_output_create(&output->base, output->display) < 0)
1095 wl_list_insert(compositor->base.output_list.prev, &output->base.link);
1097 weston_log("Raspberry Pi HDMI output %dx%d px\n",
1098 output->mode.width, output->mode.height);
1099 weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
1100 output->mode.refresh / 1000);
1101 weston_log_continue(STAMP_SPACE "orientation: %s\n",
1102 transform2str(output->base.transform));
1104 if (!strncmp(transform2str(output->base.transform), "flipped", 7))
1105 weston_log("warning: flipped output transforms may not work\n");
1110 weston_output_destroy(&output->base);
1113 vc_dispmanx_display_close(output->display);
1116 rpi_flippipe_release(&output->flippipe);
1124 rpi_led_update(struct weston_seat *seat_base, enum weston_led leds)
1126 struct rpi_seat *seat = to_rpi_seat(seat_base);
1127 struct evdev_device *device;
1129 wl_list_for_each(device, &seat->devices_list, link)
1130 evdev_led_update(device, leds);
1133 static const char default_seat[] = "seat0";
1136 device_added(struct udev_device *udev_device, struct rpi_seat *master)
1138 struct evdev_device *device;
1139 const char *devnode;
1140 const char *device_seat;
1143 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1145 device_seat = default_seat;
1147 if (strcmp(device_seat, master->seat_id))
1150 devnode = udev_device_get_devnode(udev_device);
1152 /* Use non-blocking mode so that we can loop on read on
1153 * evdev_device_data() until all events on the fd are
1154 * read. mtdev_get() also expects this. */
1155 fd = open(devnode, O_RDWR | O_NONBLOCK | O_CLOEXEC);
1157 weston_log("opening input device '%s' failed.\n", devnode);
1161 device = evdev_device_create(&master->base, devnode, fd);
1164 weston_log("not using input device '%s'.\n", devnode);
1168 wl_list_insert(master->devices_list.prev, &device->link);
1172 evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1174 struct rpi_seat *seat = to_rpi_seat(seat_base);
1175 struct udev_enumerate *e;
1176 struct udev_list_entry *entry;
1177 struct udev_device *device;
1178 const char *path, *sysname;
1180 e = udev_enumerate_new(udev);
1181 udev_enumerate_add_match_subsystem(e, "input");
1182 udev_enumerate_scan_devices(e);
1183 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1184 path = udev_list_entry_get_name(entry);
1185 device = udev_device_new_from_syspath(udev, path);
1187 sysname = udev_device_get_sysname(device);
1188 if (strncmp("event", sysname, 5) != 0) {
1189 udev_device_unref(device);
1193 device_added(device, seat);
1195 udev_device_unref(device);
1197 udev_enumerate_unref(e);
1199 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1201 if (wl_list_empty(&seat->devices_list)) {
1203 "warning: no input devices on entering Weston. "
1204 "Possible causes:\n"
1205 "\t- no permissions to read /dev/input/event*\n"
1206 "\t- seats misconfigured "
1207 "(Weston backend option 'seat', "
1208 "udev device property ID_SEAT)\n");
1213 evdev_udev_handler(int fd, uint32_t mask, void *data)
1215 struct rpi_seat *seat = data;
1216 struct udev_device *udev_device;
1217 struct evdev_device *device, *next;
1219 const char *devnode;
1221 udev_device = udev_monitor_receive_device(seat->udev_monitor);
1225 action = udev_device_get_action(udev_device);
1229 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1232 if (!strcmp(action, "add")) {
1233 device_added(udev_device, seat);
1235 else if (!strcmp(action, "remove")) {
1236 devnode = udev_device_get_devnode(udev_device);
1237 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1238 if (!strcmp(device->devnode, devnode)) {
1239 weston_log("input device %s, %s removed\n",
1240 device->devname, device->devnode);
1241 evdev_device_destroy(device);
1247 udev_device_unref(udev_device);
1253 evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1255 struct rpi_seat *master = to_rpi_seat(seat_base);
1256 struct wl_event_loop *loop;
1257 struct weston_compositor *c = master->base.compositor;
1260 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1261 if (!master->udev_monitor) {
1262 weston_log("udev: failed to create the udev monitor\n");
1266 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1269 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1270 weston_log("udev: failed to bind the udev monitor\n");
1271 udev_monitor_unref(master->udev_monitor);
1275 loop = wl_display_get_event_loop(c->wl_display);
1276 fd = udev_monitor_get_fd(master->udev_monitor);
1277 master->udev_monitor_source =
1278 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1279 evdev_udev_handler, master);
1280 if (!master->udev_monitor_source) {
1281 udev_monitor_unref(master->udev_monitor);
1289 evdev_disable_udev_monitor(struct weston_seat *seat_base)
1291 struct rpi_seat *seat = to_rpi_seat(seat_base);
1293 if (!seat->udev_monitor)
1296 udev_monitor_unref(seat->udev_monitor);
1297 seat->udev_monitor = NULL;
1298 wl_event_source_remove(seat->udev_monitor_source);
1299 seat->udev_monitor_source = NULL;
1303 evdev_input_create(struct weston_compositor *c, struct udev *udev,
1304 const char *seat_id)
1306 struct rpi_seat *seat;
1308 seat = malloc(sizeof *seat);
1312 memset(seat, 0, sizeof *seat);
1313 weston_seat_init(&seat->base, c);
1314 seat->base.led_update = rpi_led_update;
1316 wl_list_init(&seat->devices_list);
1317 seat->seat_id = strdup(seat_id);
1318 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1319 free(seat->seat_id);
1324 evdev_add_devices(udev, &seat->base);
1328 evdev_remove_devices(struct weston_seat *seat_base)
1330 struct rpi_seat *seat = to_rpi_seat(seat_base);
1331 struct evdev_device *device, *next;
1333 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1334 evdev_device_destroy(device);
1336 if (seat->base.keyboard)
1337 notify_keyboard_focus_out(&seat->base);
1341 evdev_input_destroy(struct weston_seat *seat_base)
1343 struct rpi_seat *seat = to_rpi_seat(seat_base);
1345 evdev_remove_devices(seat_base);
1346 evdev_disable_udev_monitor(&seat->base);
1348 weston_seat_release(seat_base);
1349 free(seat->seat_id);
1354 rpi_compositor_destroy(struct weston_compositor *base)
1356 struct rpi_compositor *compositor = to_rpi_compositor(base);
1357 struct weston_seat *seat, *next;
1359 wl_list_for_each_safe(seat, next, &compositor->base.seat_list, link)
1360 evdev_input_destroy(seat);
1362 /* destroys outputs, too */
1363 weston_compositor_shutdown(&compositor->base);
1365 compositor->base.renderer->destroy(&compositor->base);
1366 tty_destroy(compositor->tty);
1373 vt_func(struct weston_compositor *base, int event)
1375 struct rpi_compositor *compositor = to_rpi_compositor(base);
1376 struct weston_seat *seat;
1377 struct weston_output *output;
1381 weston_log("entering VT\n");
1382 compositor->base.focus = 1;
1383 compositor->base.state = compositor->prev_state;
1384 weston_compositor_damage_all(&compositor->base);
1385 wl_list_for_each(seat, &compositor->base.seat_list, link) {
1386 evdev_add_devices(compositor->udev, seat);
1387 evdev_enable_udev_monitor(compositor->udev, seat);
1391 weston_log("leaving VT\n");
1392 wl_list_for_each(seat, &compositor->base.seat_list, link) {
1393 evdev_disable_udev_monitor(seat);
1394 evdev_remove_devices(seat);
1397 compositor->base.focus = 0;
1398 compositor->prev_state = compositor->base.state;
1399 weston_compositor_offscreen(&compositor->base);
1401 /* If we have a repaint scheduled (either from a
1402 * pending pageflip or the idle handler), make sure we
1403 * cancel that so we don't try to pageflip when we're
1404 * vt switched away. The OFFSCREEN state will prevent
1405 * further attemps at repainting. When we switch
1406 * back, we schedule a repaint, which will process
1407 * pending frame callbacks. */
1409 wl_list_for_each(output,
1410 &compositor->base.output_list, link) {
1411 output->repaint_needed = 0;
1419 rpi_restore(struct weston_compositor *base)
1421 struct rpi_compositor *compositor = to_rpi_compositor(base);
1423 tty_reset(compositor->tty);
1427 switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
1429 struct rpi_compositor *ec = data;
1431 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
1434 struct rpi_parameters {
1437 struct rpi_renderer_parameters renderer;
1438 uint32_t output_transform;
1441 static struct weston_compositor *
1442 rpi_compositor_create(struct wl_display *display, int *argc, char *argv[],
1443 int config_fd, struct rpi_parameters *param)
1445 struct rpi_compositor *compositor;
1446 const char *seat = default_seat;
1449 weston_log("initializing Raspberry Pi backend\n");
1451 compositor = calloc(1, sizeof *compositor);
1452 if (compositor == NULL)
1455 if (weston_compositor_init(&compositor->base, display, argc, argv,
1459 compositor->udev = udev_new();
1460 if (compositor->udev == NULL) {
1461 weston_log("Failed to initialize udev context.\n");
1462 goto out_compositor;
1465 compositor->tty = tty_create(&compositor->base, vt_func, param->tty);
1466 if (!compositor->tty) {
1467 weston_log("Failed to initialize tty.\n");
1471 compositor->base.destroy = rpi_compositor_destroy;
1472 compositor->base.restore = rpi_restore;
1474 compositor->base.focus = 1;
1475 compositor->prev_state = WESTON_COMPOSITOR_ACTIVE;
1476 compositor->max_planes = int_max(param->max_planes, 0);
1477 compositor->single_buffer = param->renderer.single_buffer;
1479 weston_log("Maximum number of additional Dispmanx planes: %d\n",
1480 compositor->max_planes);
1481 weston_log("Dispmanx planes are %s buffered.\n",
1482 compositor->single_buffer ? "single" : "double");
1484 for (key = KEY_F1; key < KEY_F9; key++)
1485 weston_compositor_add_key_binding(&compositor->base, key,
1486 MODIFIER_CTRL | MODIFIER_ALT,
1487 switch_vt_binding, compositor);
1490 * bcm_host_init() creates threads.
1491 * Therefore we must have all signal handlers set and signals blocked
1492 * before calling it. Otherwise the signals may end in the bcm
1493 * threads and cause the default behaviour there. For instance,
1494 * SIGUSR1 used for VT switching caused Weston to terminate there.
1498 if (rpi_renderer_create(&compositor->base, ¶m->renderer) < 0)
1501 if (rpi_output_create(compositor, param->output_transform) < 0)
1504 evdev_input_create(&compositor->base, compositor->udev, seat);
1506 return &compositor->base;
1509 compositor->base.renderer->destroy(&compositor->base);
1512 tty_destroy(compositor->tty);
1515 udev_unref(compositor->udev);
1518 weston_compositor_shutdown(&compositor->base);
1528 * If you have a recent enough firmware in Raspberry Pi, that
1529 * supports falling back to off-line hardware compositing, and
1530 * you have enabled it with dispmanx_offline=1 in /boot/config.txt,
1531 * then VideoCore should be able to handle almost 100 Dispmanx
1532 * elements. Therefore use 80 as the default limit.
1534 * If you don't have off-line compositing support, this would be
1535 * better as something like 10. Failing on-line compositing may
1536 * show up as visible glitches, HDMI blanking, or invisible surfaces.
1538 * When the max-planes number is reached, rpi-backend will start
1539 * to fall back to GLESv2 compositing.
1541 #define DEFAULT_MAX_PLANES 80
1543 WL_EXPORT struct weston_compositor *
1544 backend_init(struct wl_display *display, int *argc, char *argv[],
1547 const char *transform = "normal";
1550 struct rpi_parameters param = {
1551 .tty = 0, /* default to current tty */
1552 .max_planes = DEFAULT_MAX_PLANES,
1553 .renderer.single_buffer = 0,
1554 .output_transform = WL_OUTPUT_TRANSFORM_NORMAL,
1557 const struct weston_option rpi_options[] = {
1558 { WESTON_OPTION_INTEGER, "tty", 0, ¶m.tty },
1559 { WESTON_OPTION_INTEGER, "max-planes", 0, ¶m.max_planes },
1560 { WESTON_OPTION_BOOLEAN, "single-buffer", 0,
1561 ¶m.renderer.single_buffer },
1562 { WESTON_OPTION_STRING, "transform", 0, &transform },
1565 parse_options(rpi_options, ARRAY_LENGTH(rpi_options), argc, argv);
1567 ret = str2transform(transform);
1569 weston_log("invalid transform \"%s\"\n", transform);
1571 param.output_transform = ret;
1573 return rpi_compositor_create(display, argc, argv, config_fd, ¶m);