diff --git a/Makefile.am b/Makefile.am index 00b74e5d..8ee9c8d6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -328,40 +328,6 @@ nodist_wayland_backend_la_SOURCES = \ protocol/fullscreen-shell-unstable-v1-client-protocol.h endif -if ENABLE_RPI_COMPOSITOR -if INSTALL_RPI_COMPOSITOR -module_LTLIBRARIES += rpi-backend.la -else -noinst_LTLIBRARIES += rpi-backend.la -endif - -rpi_backend_la_LDFLAGS = -module -avoid-version -rpi_backend_la_LIBADD = $(COMPOSITOR_LIBS) \ - $(RPI_COMPOSITOR_LIBS) \ - $(RPI_BCM_HOST_LIBS) \ - $(INPUT_BACKEND_LIBS) \ - libsession-helper.la \ - libshared.la -rpi_backend_la_CFLAGS = \ - $(AM_CFLAGS) \ - $(COMPOSITOR_CFLAGS) \ - $(RPI_COMPOSITOR_CFLAGS) \ - $(RPI_BCM_HOST_CFLAGS) -rpi_backend_la_SOURCES = \ - src/compositor-rpi.c \ - src/rpi-renderer.c \ - src/rpi-renderer.h \ - src/rpi-bcm-stubs.h \ - shared/helpers.h \ - $(INPUT_BACKEND_SOURCES) - -if ENABLE_EGL -rpi_backend_la_LIBADD += $(EGL_LIBS) -rpi_backend_la_CFLAGS += $(EGL_CFLAGS) -endif - -endif - if ENABLE_HEADLESS_COMPOSITOR module_LTLIBRARIES += headless-backend.la headless_backend_la_LDFLAGS = -module -avoid-version diff --git a/README b/README index 3fdfb37f..110a14bb 100644 --- a/README +++ b/README @@ -138,8 +138,6 @@ would be roughly like this: - xwayland (depends on X11/xcb libs) -- rpi-backend (depends on DispmanX, libudev, ...) - - fbdev-backend (depends on libudev...) - rdp-backend (depends on freerdp) diff --git a/configure.ac b/configure.ac index 87e67fed..525810f1 100644 --- a/configure.ac +++ b/configure.ac @@ -208,23 +208,6 @@ if test x$enable_headless_compositor = xyes; then fi -AC_ARG_ENABLE(rpi-compositor, - AS_HELP_STRING([--disable-rpi-compositor], - [do not build the Raspberry Pi backend]),, - enable_rpi_compositor=yes) -AM_CONDITIONAL(ENABLE_RPI_COMPOSITOR, test "x$enable_rpi_compositor" = "xyes") -have_bcm_host="no" -if test "x$enable_rpi_compositor" = "xyes"; then - AC_DEFINE([BUILD_RPI_COMPOSITOR], [1], [Build the compositor for Raspberry Pi]) - PKG_CHECK_MODULES(RPI_COMPOSITOR, [libudev >= 136 mtdev >= 1.1.0]) - PKG_CHECK_MODULES(RPI_BCM_HOST, [bcm_host], - [have_bcm_host="yes" - AC_DEFINE([HAVE_BCM_HOST], [1], [have Raspberry Pi BCM headers])], - [AC_MSG_WARN([Raspberry Pi BCM host libraries not found, will use stubs instead.])]) -fi -AM_CONDITIONAL(INSTALL_RPI_COMPOSITOR, test "x$have_bcm_host" = "xyes") - - AC_ARG_ENABLE([fbdev-compositor], [ --enable-fbdev-compositor],, enable_fbdev_compositor=yes) AM_CONDITIONAL([ENABLE_FBDEV_COMPOSITOR], @@ -678,7 +661,6 @@ AC_MSG_RESULT([ X11 Compositor ${enable_x11_compositor} Wayland Compositor ${enable_wayland_compositor} Headless Compositor ${enable_headless_compositor} - RPI Compositor ${enable_rpi_compositor} FBDEV Compositor ${enable_fbdev_compositor} RDP Compositor ${enable_rdp_compositor} Screen Sharing ${enable_screen_sharing} diff --git a/man/weston.ini.man b/man/weston.ini.man index d7c4a6fe..7aa78105 100644 --- a/man/weston.ini.man +++ b/man/weston.ini.man @@ -130,7 +130,6 @@ directory are: .BR fbdev-backend.so .BR headless-backend.so .BR rdp-backend.so -.BR rpi-backend.so .BR wayland-backend.so .BR x11-backend.so .fi diff --git a/src/compositor-rpi.c b/src/compositor-rpi.c deleted file mode 100644 index 75b808ea..00000000 --- a/src/compositor-rpi.c +++ /dev/null @@ -1,575 +0,0 @@ -/* - * Copyright © 2008-2011 Kristian Høgsberg - * Copyright © 2011 Intel Corporation - * Copyright © 2012-2013 Raspberry Pi Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef HAVE_BCM_HOST -# include -#else -# include "rpi-bcm-stubs.h" -#endif - -#include "shared/helpers.h" -#include "compositor.h" -#include "rpi-renderer.h" -#include "launcher-util.h" -#include "libinput-seat.h" -#include "presentation-time-server-protocol.h" - -#if 0 -#define DBG(...) \ - weston_log(__VA_ARGS__) -#else -#define DBG(...) do {} while (0) -#endif - -struct rpi_backend; -struct rpi_output; - -struct rpi_flippipe { - int readfd; - int writefd; - clockid_t clk_id; - struct wl_event_source *source; -}; - -struct rpi_output { - struct rpi_backend *backend; - struct weston_output base; - int single_buffer; - - struct weston_mode mode; - struct rpi_flippipe flippipe; - - DISPMANX_DISPLAY_HANDLE_T display; -}; - -struct rpi_seat { - struct weston_seat base; - struct wl_list devices_list; - - struct udev_monitor *udev_monitor; - struct wl_event_source *udev_monitor_source; - char *seat_id; -}; - -struct rpi_backend { - struct weston_backend base; - struct weston_compositor *compositor; - uint32_t prev_state; - - struct udev *udev; - struct udev_input input; - struct wl_listener session_listener; - - int single_buffer; -}; - -static inline struct rpi_output * -to_rpi_output(struct weston_output *base) -{ - return container_of(base, struct rpi_output, base); -} - -static inline struct rpi_seat * -to_rpi_seat(struct weston_seat *base) -{ - return container_of(base, struct rpi_seat, base); -} - -static inline struct rpi_backend * -to_rpi_backend(struct weston_compositor *c) -{ - return container_of(c->backend, struct rpi_backend, base); -} - -static void -rpi_flippipe_update_complete(DISPMANX_UPDATE_HANDLE_T update, void *data) -{ - /* This function runs in a different thread. */ - struct rpi_flippipe *flippipe = data; - struct timespec ts; - ssize_t ret; - - /* manufacture flip completion timestamp */ - clock_gettime(flippipe->clk_id, &ts); - - ret = write(flippipe->writefd, &ts, sizeof ts); - if (ret != sizeof ts) - weston_log("ERROR: %s failed to write, ret %zd, errno %d\n", - __func__, ret, errno); -} - -static int -rpi_dispmanx_update_submit(DISPMANX_UPDATE_HANDLE_T update, - struct rpi_output *output) -{ - /* - * The callback registered here will eventually be called - * in a different thread context. Therefore we cannot call - * the usual functions from rpi_flippipe_update_complete(). - * Instead, we have a pipe for passing the message from the - * thread, waking up the Weston main event loop, calling - * rpi_flippipe_handler(), and then ending up in - * rpi_output_update_complete() in the main thread context, - * where we can do the frame finishing work. - */ - return vc_dispmanx_update_submit(update, rpi_flippipe_update_complete, - &output->flippipe); -} - -static void -rpi_output_update_complete(struct rpi_output *output, - const struct timespec *stamp); - -static int -rpi_flippipe_handler(int fd, uint32_t mask, void *data) -{ - struct rpi_output *output = data; - ssize_t ret; - struct timespec ts; - - if (mask != WL_EVENT_READABLE) - weston_log("ERROR: unexpected mask 0x%x in %s\n", - mask, __func__); - - ret = read(fd, &ts, sizeof ts); - if (ret != sizeof ts) { - weston_log("ERROR: %s failed to read, ret %zd, errno %d\n", - __func__, ret, errno); - } - - rpi_output_update_complete(output, &ts); - - return 1; -} - -static int -rpi_flippipe_init(struct rpi_flippipe *flippipe, struct rpi_output *output) -{ - struct weston_compositor *compositor = output->backend->compositor; - struct wl_event_loop *loop; - int fd[2]; - - if (pipe2(fd, O_CLOEXEC) == -1) - return -1; - - flippipe->readfd = fd[0]; - flippipe->writefd = fd[1]; - flippipe->clk_id = compositor->presentation_clock; - - loop = wl_display_get_event_loop(compositor->wl_display); - flippipe->source = wl_event_loop_add_fd(loop, flippipe->readfd, - WL_EVENT_READABLE, - rpi_flippipe_handler, output); - - if (!flippipe->source) { - close(flippipe->readfd); - close(flippipe->writefd); - return -1; - } - - return 0; -} - -static void -rpi_flippipe_release(struct rpi_flippipe *flippipe) -{ - wl_event_source_remove(flippipe->source); - close(flippipe->readfd); - close(flippipe->writefd); -} - -static void -rpi_output_start_repaint_loop(struct weston_output *output) -{ - struct timespec ts; - - /* XXX: do a phony dispmanx update and trigger on its completion? */ - weston_compositor_read_presentation_clock(output->compositor, &ts); - weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID); -} - -static int -rpi_output_repaint(struct weston_output *base, pixman_region32_t *damage) -{ - struct rpi_output *output = to_rpi_output(base); - struct weston_compositor *compositor = output->backend->compositor; - struct weston_plane *primary_plane = &compositor->primary_plane; - DISPMANX_UPDATE_HANDLE_T update; - - DBG("frame update start\n"); - - /* Update priority higher than in rpi-renderer's - * output destroy function, see rpi_output_destroy(). - */ - update = vc_dispmanx_update_start(1); - - rpi_renderer_set_update_handle(&output->base, update); - compositor->renderer->repaint_output(&output->base, damage); - - pixman_region32_subtract(&primary_plane->damage, - &primary_plane->damage, damage); - - /* schedule callback to rpi_output_update_complete() */ - rpi_dispmanx_update_submit(update, output); - DBG("frame update submitted\n"); - return 0; -} - -static void -rpi_output_update_complete(struct rpi_output *output, - const struct timespec *stamp) -{ - uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC | - WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION; - - DBG("frame update complete(%ld.%09ld)\n", - (long)stamp->tv_sec, (long)stamp->tv_nsec); - rpi_renderer_finish_frame(&output->base); - weston_output_finish_frame(&output->base, stamp, flags); -} - -static void -rpi_output_destroy(struct weston_output *base) -{ - struct rpi_output *output = to_rpi_output(base); - - DBG("%s\n", __func__); - - rpi_renderer_output_destroy(base); - - /* rpi_renderer_output_destroy() will schedule a removal of - * all Dispmanx Elements, and wait for the update to complete. - * Assuming updates are sequential, the wait should guarantee, - * that any pending rpi_flippipe_update_complete() callbacks - * have happened already. Therefore we can destroy the flippipe - * now. - */ - rpi_flippipe_release(&output->flippipe); - - weston_output_destroy(&output->base); - - vc_dispmanx_display_close(output->display); - - free(output); -} - -static int -rpi_output_create(struct rpi_backend *backend, uint32_t transform) -{ - struct rpi_output *output; - DISPMANX_MODEINFO_T modeinfo; - int ret; - float mm_width, mm_height; - - output = zalloc(sizeof *output); - if (output == NULL) - return -1; - - output->backend = backend; - output->single_buffer = backend->single_buffer; - - if (rpi_flippipe_init(&output->flippipe, output) < 0) { - weston_log("Creating message pipe failed.\n"); - goto out_free; - } - - output->display = vc_dispmanx_display_open(DISPMANX_ID_HDMI); - if (!output->display) { - weston_log("Failed to open dispmanx HDMI display.\n"); - goto out_pipe; - } - - ret = vc_dispmanx_display_get_info(output->display, &modeinfo); - if (ret < 0) { - weston_log("Failed to get display mode information.\n"); - goto out_dmx_close; - } - - output->base.start_repaint_loop = rpi_output_start_repaint_loop; - output->base.repaint = rpi_output_repaint; - output->base.destroy = rpi_output_destroy; - output->base.assign_planes = NULL; - output->base.set_backlight = NULL; - output->base.set_dpms = NULL; - output->base.switch_mode = NULL; - - /* XXX: use tvservice to get information from and control the - * HDMI and SDTV outputs. See: - * /opt/vc/include/interface/vmcs_host/vc_tvservice.h - */ - - /* only one static mode in list */ - output->mode.flags = - WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED; - output->mode.width = modeinfo.width; - output->mode.height = modeinfo.height; - output->mode.refresh = 60000; - wl_list_init(&output->base.mode_list); - wl_list_insert(&output->base.mode_list, &output->mode.link); - - output->base.current_mode = &output->mode; - output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN; - output->base.make = "unknown"; - output->base.model = "unknown"; - output->base.name = strdup("rpi"); - - /* guess 96 dpi */ - mm_width = modeinfo.width * (25.4f / 96.0f); - mm_height = modeinfo.height * (25.4f / 96.0f); - - weston_output_init(&output->base, backend->compositor, - 0, 0, round(mm_width), round(mm_height), - transform, 1); - - if (rpi_renderer_output_create(&output->base, output->display) < 0) - goto out_output; - - weston_compositor_add_output(backend->compositor, &output->base); - - weston_log("Raspberry Pi HDMI output %dx%d px\n", - output->mode.width, output->mode.height); - weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n", - output->mode.refresh / 1000); - weston_log_continue(STAMP_SPACE "orientation: %s\n", - weston_transform_to_string(output->base.transform)); - - if (!strncmp(weston_transform_to_string(output->base.transform), - "flipped", 7)) - weston_log("warning: flipped output transforms may not work\n"); - - return 0; - -out_output: - weston_output_destroy(&output->base); - -out_dmx_close: - vc_dispmanx_display_close(output->display); - -out_pipe: - rpi_flippipe_release(&output->flippipe); - -out_free: - free(output); - return -1; -} - -static void -rpi_backend_destroy(struct weston_compositor *base) -{ - struct rpi_backend *backend = to_rpi_backend(base); - - udev_input_destroy(&backend->input); - - /* destroys outputs, too */ - weston_compositor_shutdown(base); - - weston_launcher_destroy(base->launcher); - - bcm_host_deinit(); - free(backend); -} - -static void -session_notify(struct wl_listener *listener, void *data) -{ - struct weston_compositor *compositor = data; - struct rpi_backend *backend = to_rpi_backend(compositor); - struct weston_output *output; - - if (compositor->session_active) { - weston_log("activating session\n"); - compositor->state = backend->prev_state; - weston_compositor_damage_all(compositor); - udev_input_enable(&backend->input); - } else { - weston_log("deactivating session\n"); - udev_input_disable(&backend->input); - - backend->prev_state = compositor->state; - weston_compositor_offscreen(compositor); - - /* If we have a repaint scheduled (either from a - * pending pageflip or the idle handler), make sure we - * cancel that so we don't try to pageflip when we're - * vt switched away. The OFFSCREEN state will prevent - * further attemps at repainting. When we switch - * back, we schedule a repaint, which will process - * pending frame callbacks. */ - - wl_list_for_each(output, - &compositor->output_list, link) { - output->repaint_needed = 0; - } - }; -} - -static void -rpi_restore(struct weston_compositor *compositor) -{ - weston_launcher_restore(compositor->launcher); -} - -struct rpi_parameters { - int tty; - struct rpi_renderer_parameters renderer; - uint32_t output_transform; -}; - -static struct rpi_backend * -rpi_backend_create(struct weston_compositor *compositor, - struct rpi_parameters *param) -{ - struct rpi_backend *backend; - - weston_log("initializing Raspberry Pi backend\n"); - - backend = zalloc(sizeof *backend); - if (backend == NULL) - return NULL; - - if (weston_compositor_set_presentation_clock_software( - compositor) < 0) - goto out_compositor; - - backend->udev = udev_new(); - if (backend->udev == NULL) { - weston_log("Failed to initialize udev context.\n"); - goto out_compositor; - } - - backend->session_listener.notify = session_notify; - wl_signal_add(&compositor->session_signal, - &backend->session_listener); - compositor->launcher = - weston_launcher_connect(compositor, param->tty, "seat0", false); - if (!compositor->launcher) { - weston_log("Failed to initialize tty.\n"); - goto out_udev; - } - - backend->base.destroy = rpi_backend_destroy; - backend->base.restore = rpi_restore; - - backend->compositor = compositor; - backend->prev_state = WESTON_COMPOSITOR_ACTIVE; - backend->single_buffer = param->renderer.single_buffer; - - weston_log("Dispmanx planes are %s buffered.\n", - backend->single_buffer ? "single" : "double"); - - weston_setup_vt_switch_bindings(compositor); - - /* - * bcm_host_init() creates threads. - * Therefore we must have all signal handlers set and signals blocked - * before calling it. Otherwise the signals may end in the bcm - * threads and cause the default behaviour there. For instance, - * SIGUSR1 used for VT switching caused Weston to terminate there. - */ - bcm_host_init(); - - if (rpi_renderer_create(compositor, ¶m->renderer) < 0) - goto out_launcher; - - if (rpi_output_create(backend, param->output_transform) < 0) - goto out_launcher; - - if (udev_input_init(&backend->input, - compositor, - backend->udev, "seat0") != 0) { - weston_log("Failed to initialize udev input.\n"); - goto out_launcher; - } - - compositor->backend = &backend->base; - - return backend; - -out_launcher: - weston_launcher_destroy(compositor->launcher); - -out_udev: - udev_unref(backend->udev); - -out_compositor: - weston_compositor_shutdown(compositor); - - bcm_host_deinit(); - free(backend); - - return NULL; -} - -WL_EXPORT int -backend_init(struct weston_compositor *compositor, - int *argc, char *argv[], - struct weston_config *config, - struct weston_backend_config *config_base) -{ - const char *transform = "normal"; - struct rpi_backend *b; - - struct rpi_parameters param = { - .tty = 0, /* default to current tty */ - .renderer.single_buffer = 0, - .output_transform = WL_OUTPUT_TRANSFORM_NORMAL, - .renderer.opaque_regions = 0, - }; - - const struct weston_option rpi_options[] = { - { WESTON_OPTION_INTEGER, "tty", 0, ¶m.tty }, - { WESTON_OPTION_BOOLEAN, "single-buffer", 0, - ¶m.renderer.single_buffer }, - { WESTON_OPTION_STRING, "transform", 0, &transform }, - { WESTON_OPTION_BOOLEAN, "opaque-regions", 0, - ¶m.renderer.opaque_regions }, - }; - - parse_options(rpi_options, ARRAY_LENGTH(rpi_options), argc, argv); - - if (weston_parse_transform(transform, ¶m.output_transform) < 0) - weston_log("invalid transform \"%s\"\n", transform); - - b = rpi_backend_create(compositor, ¶m); - if (b == NULL) - return -1; - return 0; -} diff --git a/src/main.c b/src/main.c index 3279ac6a..475c1d0f 100644 --- a/src/main.c +++ b/src/main.c @@ -252,9 +252,6 @@ usage(int error_code) #if defined(BUILD_RDP_COMPOSITOR) "\t\t\t\trdp-backend.so\n" #endif -#if defined(BUILD_RPI_COMPOSITOR) && defined(HAVE_BCM_HOST) - "\t\t\t\trpi-backend.so\n" -#endif #if defined(BUILD_WAYLAND_COMPOSITOR) "\t\t\t\twayland-backend.so\n" #endif @@ -313,18 +310,6 @@ usage(int error_code) "\n"); #endif -#if defined(BUILD_RPI_COMPOSITOR) && defined(HAVE_BCM_HOST) - fprintf(stderr, - "Options for rpi-backend.so:\n\n" - " --tty=TTY\t\tThe tty to use\n" - " --single-buffer\tUse single-buffered Dispmanx elements.\n" - " --transform=TR\tThe output transformation, TR is one of:\n" - "\tnormal 90 180 270 flipped flipped-90 flipped-180 flipped-270\n" - " --opaque-regions\tEnable support for opaque regions, can be " - "very slow without support in the GPU firmware.\n" - "\n"); -#endif - #if defined(BUILD_WAYLAND_COMPOSITOR) fprintf(stderr, "Options for wayland-backend.so:\n\n" @@ -1264,10 +1249,6 @@ load_backend(struct weston_compositor *compositor, const char *backend, return load_x11_backend(compositor, backend, argc, argv, config); else if (strstr(backend, "wayland-backend.so")) return load_wayland_backend(compositor, backend, argc, argv, config); -#if 0 - else if (strstr(backend, "rpi-backend.so")) - return load_rpi_backend(compositor, backend, argc, argv, config); -#endif return load_backend_old(compositor, backend, argc, argv, config); } diff --git a/src/rpi-bcm-stubs.h b/src/rpi-bcm-stubs.h deleted file mode 100644 index fa30570d..00000000 --- a/src/rpi-bcm-stubs.h +++ /dev/null @@ -1,327 +0,0 @@ -/* -Copyright (c) 2012, Broadcom Europe Ltd -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* - * This file provides just enough types and stubs, so that the rpi-backend - * can be built without the real headers and libraries of the Raspberry Pi. - * - * This file CANNOT be used to build a working rpi-backend, it is intended - * only for build-testing, when the proper headers are not available. - */ - -#ifndef RPI_BCM_STUBS -#define RPI_BCM_STUBS - -#include - -/* from /opt/vc/include/bcm_host.h */ - -static inline void bcm_host_init(void) {} -static inline void bcm_host_deinit(void) {} - - -/* from /opt/vc/include/interface/vmcs_host/vc_dispservice_defs.h */ - -#define TRANSFORM_HFLIP (1<<0) -#define TRANSFORM_VFLIP (1<<1) -#define TRANSFORM_TRANSPOSE (1<<2) - - -/* from /opt/vc/include/interface/vctypes/vc_display_types.h */ - -typedef enum -{ - VCOS_DISPLAY_INPUT_FORMAT_INVALID = 0, -} DISPLAY_INPUT_FORMAT_T; - -/* from /opt/vc/include/interface/vctypes/vc_image_types.h */ - -typedef struct tag_VC_RECT_T { - int32_t x; - int32_t y; - int32_t width; - int32_t height; -} VC_RECT_T; - -typedef enum { - VC_IMAGE_ROT0, - /* these are not the right values: */ - VC_IMAGE_ROT90, - VC_IMAGE_ROT180, - VC_IMAGE_ROT270, - VC_IMAGE_MIRROR_ROT0, - VC_IMAGE_MIRROR_ROT90, - VC_IMAGE_MIRROR_ROT180, - VC_IMAGE_MIRROR_ROT270, -} VC_IMAGE_TRANSFORM_T; - -typedef enum -{ - VC_IMAGE_MIN = 0, - /* these are not the right values: */ - VC_IMAGE_ARGB8888, - VC_IMAGE_XRGB8888, - VC_IMAGE_RGB565, -} VC_IMAGE_TYPE_T; - -/* from /opt/vc/include/interface/vmcs_host/vc_dispmanx_types.h */ - -typedef uint32_t DISPMANX_DISPLAY_HANDLE_T; -typedef uint32_t DISPMANX_UPDATE_HANDLE_T; -typedef uint32_t DISPMANX_ELEMENT_HANDLE_T; -typedef uint32_t DISPMANX_RESOURCE_HANDLE_T; -typedef uint32_t DISPMANX_PROTECTION_T; - -#define DISPMANX_NO_HANDLE 0 -#define DISPMANX_PROTECTION_NONE 0 -#define DISPMANX_ID_HDMI 2 - -typedef enum { - /* Bottom 2 bits sets the alpha mode */ - DISPMANX_FLAGS_ALPHA_FROM_SOURCE = 0, - DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS = 1, - DISPMANX_FLAGS_ALPHA_FIXED_NON_ZERO = 2, - DISPMANX_FLAGS_ALPHA_FIXED_EXCEED_0X07 = 3, - - DISPMANX_FLAGS_ALPHA_PREMULT = 1 << 16, - DISPMANX_FLAGS_ALPHA_MIX = 1 << 17 -} DISPMANX_FLAGS_ALPHA_T; - -typedef struct { - DISPMANX_FLAGS_ALPHA_T flags; - uint32_t opacity; - DISPMANX_RESOURCE_HANDLE_T mask; -} VC_DISPMANX_ALPHA_T; - -typedef struct { - int32_t width; - int32_t height; - VC_IMAGE_TRANSFORM_T transform; - DISPLAY_INPUT_FORMAT_T input_format; -} DISPMANX_MODEINFO_T; - -typedef enum { - DISPMANX_NO_ROTATE = 0, - DISPMANX_ROTATE_90 = 1, - DISPMANX_ROTATE_180 = 2, - DISPMANX_ROTATE_270 = 3, - - DISPMANX_FLIP_HRIZ = 1 << 16, - DISPMANX_FLIP_VERT = 1 << 17 -} DISPMANX_TRANSFORM_T; - -typedef struct { - uint32_t dummy; -} DISPMANX_CLAMP_T; - -typedef void (*DISPMANX_CALLBACK_FUNC_T)(DISPMANX_UPDATE_HANDLE_T u, - void *arg); - -/* from /opt/vc/include/interface/vmcs_host/vc_dispmanx.h */ - -static inline int -vc_dispmanx_rect_set(VC_RECT_T *rect, uint32_t x_offset, uint32_t y_offset, - uint32_t width, uint32_t height) -{ - rect->x = x_offset; - rect->y = y_offset; - rect->width = width; - rect->height = height; - return 0; -} - -static inline DISPMANX_RESOURCE_HANDLE_T -vc_dispmanx_resource_create(VC_IMAGE_TYPE_T type, uint32_t width, - uint32_t height, uint32_t *native_image_handle) -{ - return DISPMANX_NO_HANDLE; -} - -static inline int -vc_dispmanx_resource_write_data(DISPMANX_RESOURCE_HANDLE_T res, - VC_IMAGE_TYPE_T src_type, - int src_pitch, - void *src_address, - const VC_RECT_T *rect) -{ - return -1; -} - -static inline int -vc_dispmanx_resource_write_data_rect(DISPMANX_RESOURCE_HANDLE_T handle, - VC_IMAGE_TYPE_T src_type, - int src_pitch, - void *src_address, - const VC_RECT_T *src_rect, - uint32_t dst_x, - uint32_t dst_y) -{ - return -1; -} - -static inline int -vc_dispmanx_resource_read_data(DISPMANX_RESOURCE_HANDLE_T handle, - const VC_RECT_T *p_rect, - void *dst_address, - uint32_t dst_pitch) -{ - return -1; -} - -static inline int -vc_dispmanx_resource_delete(DISPMANX_RESOURCE_HANDLE_T res) -{ - return -1; -} - -static inline DISPMANX_DISPLAY_HANDLE_T -vc_dispmanx_display_open(uint32_t device) -{ - return DISPMANX_NO_HANDLE; -} - -static inline int -vc_dispmanx_display_close(DISPMANX_DISPLAY_HANDLE_T display) -{ - return -1; -} - -static inline int -vc_dispmanx_display_get_info(DISPMANX_DISPLAY_HANDLE_T display, - DISPMANX_MODEINFO_T *pinfo) -{ - return -1; -} - -static inline DISPMANX_UPDATE_HANDLE_T -vc_dispmanx_update_start(int32_t priority) -{ - return DISPMANX_NO_HANDLE; -} - -static inline DISPMANX_ELEMENT_HANDLE_T -vc_dispmanx_element_add(DISPMANX_UPDATE_HANDLE_T update, - DISPMANX_DISPLAY_HANDLE_T display, - int32_t layer, - const VC_RECT_T *dest_rect, - DISPMANX_RESOURCE_HANDLE_T src, - const VC_RECT_T *src_rect, - DISPMANX_PROTECTION_T protection, - VC_DISPMANX_ALPHA_T *alpha, - DISPMANX_CLAMP_T *clamp, - DISPMANX_TRANSFORM_T transform) -{ - return DISPMANX_NO_HANDLE; -} - -static inline int -vc_dispmanx_element_change_source(DISPMANX_UPDATE_HANDLE_T update, - DISPMANX_ELEMENT_HANDLE_T element, - DISPMANX_RESOURCE_HANDLE_T src) -{ - return -1; -} - -static inline int -vc_dispmanx_element_modified(DISPMANX_UPDATE_HANDLE_T update, - DISPMANX_ELEMENT_HANDLE_T element, - const VC_RECT_T *rect) -{ - return -1; -} - -static inline int -vc_dispmanx_element_remove(DISPMANX_UPDATE_HANDLE_T update, - DISPMANX_ELEMENT_HANDLE_T element) -{ - return -1; -} - -static inline int -vc_dispmanx_update_submit(DISPMANX_UPDATE_HANDLE_T update, - DISPMANX_CALLBACK_FUNC_T cb_func, void *cb_arg) -{ - return -1; -} - -static inline int -vc_dispmanx_update_submit_sync(DISPMANX_UPDATE_HANDLE_T update) -{ - return -1; -} - -static inline int -vc_dispmanx_element_change_attributes(DISPMANX_UPDATE_HANDLE_T update, - DISPMANX_ELEMENT_HANDLE_T element, - uint32_t change_flags, - int32_t layer, - uint8_t opacity, - const VC_RECT_T *dest_rect, - const VC_RECT_T *src_rect, - DISPMANX_RESOURCE_HANDLE_T mask, - VC_IMAGE_TRANSFORM_T transform) -{ - return -1; -} - -static inline int -vc_dispmanx_snapshot(DISPMANX_DISPLAY_HANDLE_T display, - DISPMANX_RESOURCE_HANDLE_T snapshot_resource, - VC_IMAGE_TRANSFORM_T transform) -{ - return -1; -} - -struct wl_resource; -static inline DISPMANX_RESOURCE_HANDLE_T -vc_dispmanx_get_handle_from_wl_buffer(struct wl_resource *_buffer) -{ - return DISPMANX_NO_HANDLE; -} - -static inline void -vc_dispmanx_set_wl_buffer_in_use(struct wl_resource *_buffer, int in_use) -{ -} - -static inline int -vc_dispmanx_element_set_opaque_rect(DISPMANX_UPDATE_HANDLE_T update, - DISPMANX_ELEMENT_HANDLE_T element, - const VC_RECT_T *opaque_rect) -{ - return -1; -} - -/* from /opt/vc/include/EGL/eglplatform.h */ - -typedef struct { - DISPMANX_ELEMENT_HANDLE_T element; - int width; - int height; -} EGL_DISPMANX_WINDOW_T; - -#endif /* RPI_BCM_STUBS */ diff --git a/src/rpi-renderer.c b/src/rpi-renderer.c deleted file mode 100644 index 33eb67cc..00000000 --- a/src/rpi-renderer.c +++ /dev/null @@ -1,1830 +0,0 @@ -/* - * Copyright © 2012-2013 Raspberry Pi Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "config.h" - -#include -#include -#include - -#ifdef HAVE_BCM_HOST -# include -#else -# include "rpi-bcm-stubs.h" -#endif - -#include "compositor.h" -#include "rpi-renderer.h" -#include "shared/helpers.h" - -#ifdef ENABLE_EGL -#include -#include -#include "weston-egl-ext.h" -#endif - -/* - * Dispmanx API offers alpha-blended overlays for hardware compositing. - * The final composite consists of dispmanx elements, and their contents: - * the dispmanx resource assigned to the element. The elements may be - * scanned out directly, or composited to a temporary surface, depending on - * how the firmware decides to handle the scene. Updates to multiple elements - * may be queued in a single dispmanx update object, resulting in atomic and - * vblank synchronized display updates. - * - * To avoid tearing and display artifacts, the current dispmanx resource in a - * dispmanx element must not be touched. Therefore each element must be - * double-buffered, using two resources, the front and the back. While a - * dispmanx update is running, the both resources must be considered in use. - * - * A resource may be destroyed only, when the update removing the element has - * completed. Otherwise you risk showing an incomplete composition. - */ - -#ifndef ELEMENT_CHANGE_LAYER -/* copied from interface/vmcs_host/vc_vchi_dispmanx.h of userland.git */ -#define ELEMENT_CHANGE_LAYER (1<<0) -#define ELEMENT_CHANGE_OPACITY (1<<1) -#define ELEMENT_CHANGE_DEST_RECT (1<<2) -#define ELEMENT_CHANGE_SRC_RECT (1<<3) -#define ELEMENT_CHANGE_MASK_RESOURCE (1<<4) -#define ELEMENT_CHANGE_TRANSFORM (1<<5) -#endif - -#if 0 -#define DBG(...) \ - weston_log(__VA_ARGS__) -#else -#define DBG(...) do {} while (0) -#endif - -/* If we had a fully featured vc_dispmanx_resource_write_data()... */ -/*#define HAVE_RESOURCE_WRITE_DATA_RECT 1*/ - -/* If we had a vc_dispmanx_element_set_opaque_rect()... */ -/*#define HAVE_ELEMENT_SET_OPAQUE_RECT 1*/ - -struct rpi_resource { - DISPMANX_RESOURCE_HANDLE_T handle; - int width; - int height; /* height of the image (valid pixel data) */ - int stride; /* bytes */ - int buffer_height; /* height of the buffer */ - int enable_opaque_regions; - VC_IMAGE_TYPE_T ifmt; -}; - -struct rpir_output; - -struct rpir_egl_buffer { - struct weston_buffer_reference buffer_ref; - DISPMANX_RESOURCE_HANDLE_T resource_handle; -}; - -enum buffer_type { - BUFFER_TYPE_NULL, - BUFFER_TYPE_SHM, - BUFFER_TYPE_EGL -}; - -struct rpir_surface { - struct weston_surface *surface; - - struct wl_list views; - int visible_views; - int need_swap; - int single_buffer; - int enable_opaque_regions; - - struct rpi_resource resources[2]; - struct rpi_resource *front; - struct rpi_resource *back; - pixman_region32_t prev_damage; - - struct rpir_egl_buffer *egl_front; - struct rpir_egl_buffer *egl_back; - struct rpir_egl_buffer *egl_old_front; - - struct weston_buffer_reference buffer_ref; - enum buffer_type buffer_type; - - struct wl_listener surface_destroy_listener; -}; - -struct rpir_view { - struct rpir_surface *surface; - struct wl_list surface_link; - struct weston_view *view; - - /* If link is empty, the view is guaranteed to not be on screen, - * i.e. updates removing Elements have completed. - */ - struct wl_list link; - - DISPMANX_ELEMENT_HANDLE_T handle; - int layer; - - struct wl_listener view_destroy_listener; -}; - -struct rpir_output { - DISPMANX_DISPLAY_HANDLE_T display; - - DISPMANX_UPDATE_HANDLE_T update; - - /* all Elements currently on screen */ - struct wl_list view_list; /* struct rpir_surface::link */ - - /* Elements just removed, waiting for update completion */ - struct wl_list view_cleanup_list; /* struct rpir_surface::link */ - - struct rpi_resource capture_buffer; - uint8_t *capture_data; -}; - -struct rpi_renderer { - struct weston_renderer base; - - int single_buffer; - int enable_opaque_regions; - -#ifdef ENABLE_EGL - EGLDisplay egl_display; - - PFNEGLBINDWAYLANDDISPLAYWL bind_display; - PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display; - PFNEGLQUERYWAYLANDBUFFERWL query_buffer; -#endif - int has_bind_display; -}; - -static int -rpi_renderer_create_surface(struct weston_surface *base); - -static int -rpi_renderer_create_view(struct weston_view *base); - -static void -rpir_view_handle_view_destroy(struct wl_listener *listener, void *data); - -static inline struct rpir_surface * -to_rpir_surface(struct weston_surface *surface) -{ - if (!surface->renderer_state) - rpi_renderer_create_surface(surface); - - return surface->renderer_state; -} - -static inline struct rpir_view * -to_rpir_view(struct weston_view *view) -{ - if (!view->renderer_state) - rpi_renderer_create_view(view); - - return view->renderer_state; -} - -static inline struct rpir_output * -to_rpir_output(struct weston_output *output) -{ - return output->renderer_state; -} - -static inline struct rpi_renderer * -to_rpi_renderer(struct weston_compositor *compositor) -{ - return container_of(compositor->renderer, struct rpi_renderer, base); -} - -static inline int -int_max(int a, int b) -{ - return a > b ? a : b; -} - -static inline void -int_swap(int *a, int *b) -{ - int tmp = *a; - *a = *b; - *b = tmp; -} - -static uint8_t -float2uint8(float f) -{ - int v = roundf(f * 255.0f); - - return v < 0 ? 0 : (v > 255 ? 255 : v); -} - -static void -rpi_resource_init(struct rpi_resource *resource) -{ - resource->handle = DISPMANX_NO_HANDLE; -} - -static void -rpi_resource_release(struct rpi_resource *resource) -{ - if (resource->handle == DISPMANX_NO_HANDLE) - return; - - vc_dispmanx_resource_delete(resource->handle); - DBG("resource %p release\n", resource); - resource->handle = DISPMANX_NO_HANDLE; -} - -static int -rpi_resource_realloc(struct rpi_resource *resource, VC_IMAGE_TYPE_T ifmt, - int width, int height, int stride, int buffer_height) -{ - uint32_t dummy; - - if (resource->handle != DISPMANX_NO_HANDLE && - resource->width == width && - resource->height == height && - resource->stride == stride && - resource->buffer_height == buffer_height && - resource->ifmt == ifmt) - return 0; - - rpi_resource_release(resource); - - /* NOTE: if stride is not a multiple of 16 pixels in bytes, - * the vc_image_* functions may break. Dispmanx elements - * should be fine, though. Buffer_height probably has similar - * constraints, too. - */ - resource->handle = - vc_dispmanx_resource_create(ifmt, - width | (stride << 16), - height | (buffer_height << 16), - &dummy); - if (resource->handle == DISPMANX_NO_HANDLE) - return -1; - - resource->width = width; - resource->height = height; - resource->stride = stride; - resource->buffer_height = buffer_height; - resource->ifmt = ifmt; - DBG("resource %p alloc\n", resource); - return 1; -} - -/* A firmware workaround for broken ALPHA_PREMULT + ALPHA_MIX hardware. */ -#define PREMULT_ALPHA_FLAG (1 << 31) - -static VC_IMAGE_TYPE_T -shm_buffer_get_vc_format(struct wl_shm_buffer *buffer) -{ - switch (wl_shm_buffer_get_format(buffer)) { - case WL_SHM_FORMAT_XRGB8888: - return VC_IMAGE_XRGB8888; - case WL_SHM_FORMAT_ARGB8888: - return VC_IMAGE_ARGB8888 | PREMULT_ALPHA_FLAG; - case WL_SHM_FORMAT_RGB565: - return VC_IMAGE_RGB565; - default: - /* invalid format */ - return VC_IMAGE_MIN; - } -} - -#ifndef HAVE_ELEMENT_SET_OPAQUE_RECT -static uint32_t * -apply_opaque_region(struct wl_shm_buffer *buffer, - pixman_region32_t *opaque_region) -{ - uint32_t *src, *dst; - int width; - int height; - int stride; - int x, y; - - width = wl_shm_buffer_get_width(buffer); - height = wl_shm_buffer_get_height(buffer); - stride = wl_shm_buffer_get_stride(buffer); - src = wl_shm_buffer_get_data(buffer); - - dst = malloc(height * stride); - if (dst == NULL) { - weston_log("rpi-renderer error: out of memory\n"); - return NULL; - } - - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - int i = y * stride / 4 + x; - if (pixman_region32_contains_point (opaque_region, x, y, NULL)) { - dst[i] = src[i] | 0xff000000; - } else { - dst[i] = src[i]; - } - } - } - - return dst; -} -#endif - -static int -rpi_resource_update(struct rpi_resource *resource, struct weston_buffer *buffer, - pixman_region32_t *region, pixman_region32_t *opaque_region) -{ - pixman_region32_t write_region; - pixman_box32_t *r; - VC_RECT_T rect; - VC_IMAGE_TYPE_T ifmt; - uint32_t *pixels; - int width; - int height; - int stride; - int ret; - int applied_opaque_region = 0; -#ifdef HAVE_RESOURCE_WRITE_DATA_RECT - int n; -#endif - - if (!buffer) - return -1; - - ifmt = shm_buffer_get_vc_format(buffer->shm_buffer); - width = wl_shm_buffer_get_width(buffer->shm_buffer); - height = wl_shm_buffer_get_height(buffer->shm_buffer); - stride = wl_shm_buffer_get_stride(buffer->shm_buffer); - pixels = wl_shm_buffer_get_data(buffer->shm_buffer); - -#ifndef HAVE_ELEMENT_SET_OPAQUE_RECT - if (pixman_region32_not_empty(opaque_region) && - wl_shm_buffer_get_format(buffer->shm_buffer) == WL_SHM_FORMAT_ARGB8888 && - resource->enable_opaque_regions) { - pixels = apply_opaque_region(buffer->shm_buffer, opaque_region); - - if (!pixels) - return -1; - - applied_opaque_region = 1; - } -#endif - - ret = rpi_resource_realloc(resource, ifmt & ~PREMULT_ALPHA_FLAG, - width, height, stride, height); - if (ret < 0) { - if (applied_opaque_region) - free(pixels); - return -1; - } - - pixman_region32_init_rect(&write_region, 0, 0, width, height); - if (ret == 0) - pixman_region32_intersect(&write_region, - &write_region, region); - - wl_shm_buffer_begin_access(buffer->shm_buffer); - -#ifdef HAVE_RESOURCE_WRITE_DATA_RECT - /* XXX: Can this do a format conversion, so that scanout does not have to? */ - r = pixman_region32_rectangles(&write_region, &n); - while (n--) { - vc_dispmanx_rect_set(&rect, r[n].x1, r[n].y1, - r[n].x2 - r[n].x1, r[n].y2 - r[n].y1); - - ret = vc_dispmanx_resource_write_data_rect(resource->handle, - ifmt, stride, - pixels, &rect, - rect.x, rect.y); - DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource, - rect.width, rect.height, rect.x, rect.y, ret); - if (ret) - break; - } -#else - /* vc_dispmanx_resource_write_data() ignores ifmt, - * rect.x, rect.width, and uses stride only for computing - * the size of the transfer as rect.height * stride. - * Therefore we can only write rows starting at x=0. - * To be able to write more than one scanline at a time, - * the resource must have been created with the same stride - * as used here, and we must write full scanlines. - */ - - r = pixman_region32_extents(&write_region); - vc_dispmanx_rect_set(&rect, 0, r->y1, width, r->y2 - r->y1); - ret = vc_dispmanx_resource_write_data(resource->handle, - ifmt, stride, pixels, &rect); - DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource, - width, r->y2 - r->y1, 0, r->y1, ret); -#endif - - wl_shm_buffer_end_access(buffer->shm_buffer); - - pixman_region32_fini(&write_region); - - if (applied_opaque_region) - free(pixels); - - return ret ? -1 : 0; -} - -static inline void -rpi_buffer_egl_lock(struct weston_buffer *buffer) -{ -#ifdef ENABLE_EGL - vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 1); -#endif -} - -static inline void -rpi_buffer_egl_unlock(struct weston_buffer *buffer) -{ -#ifdef ENABLE_EGL - vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 0); -#endif -} - -static void -rpir_egl_buffer_destroy(struct rpir_egl_buffer *egl_buffer) -{ - struct weston_buffer *buffer; - - if (egl_buffer == NULL) - return; - - buffer = egl_buffer->buffer_ref.buffer; - if (buffer == NULL) { - /* The client has already destroyed the wl_buffer, the - * compositor has the responsibility to delete the resource. - */ - vc_dispmanx_resource_delete(egl_buffer->resource_handle); - } else { - rpi_buffer_egl_unlock(buffer); - weston_buffer_reference(&egl_buffer->buffer_ref, NULL); - } - - free(egl_buffer); -} - -static struct rpir_surface * -rpir_surface_create(struct rpi_renderer *renderer) -{ - struct rpir_surface *surface; - - surface = zalloc(sizeof *surface); - if (surface == NULL) - return NULL; - - wl_list_init(&surface->views); - surface->single_buffer = renderer->single_buffer; - surface->enable_opaque_regions = renderer->enable_opaque_regions; - rpi_resource_init(&surface->resources[0]); - rpi_resource_init(&surface->resources[1]); - surface->front = &surface->resources[0]; - if (surface->single_buffer) - surface->back = &surface->resources[0]; - else - surface->back = &surface->resources[1]; - - surface->front->enable_opaque_regions = renderer->enable_opaque_regions; - surface->back->enable_opaque_regions = renderer->enable_opaque_regions; - - surface->buffer_type = BUFFER_TYPE_NULL; - - pixman_region32_init(&surface->prev_damage); - - return surface; -} - -static void -rpir_surface_destroy(struct rpir_surface *surface) -{ - if (surface->visible_views) - weston_log("ERROR rpi: destroying on-screen element\n"); - - assert(wl_list_empty(&surface->views)); - - if (surface->surface) - surface->surface->renderer_state = NULL; - - pixman_region32_fini(&surface->prev_damage); - rpi_resource_release(&surface->resources[0]); - rpi_resource_release(&surface->resources[1]); - DBG("rpir_surface %p destroyed (%u)\n", surface, surface->visible_views); - - rpir_egl_buffer_destroy(surface->egl_back); - rpir_egl_buffer_destroy(surface->egl_front); - rpir_egl_buffer_destroy(surface->egl_old_front); - - free(surface); -} - -static int -rpir_surface_damage(struct rpir_surface *surface, struct weston_buffer *buffer, - pixman_region32_t *damage) -{ - pixman_region32_t upload; - int ret; - - if (!pixman_region32_not_empty(damage)) - return 0; - - DBG("rpir_surface %p update resource %p\n", surface, surface->back); - - /* XXX: todo: if no surface->handle, update front buffer directly - * to avoid creating a new back buffer */ - if (surface->single_buffer) { - ret = rpi_resource_update(surface->front, buffer, damage, - &surface->surface->opaque); - } else { - pixman_region32_init(&upload); - pixman_region32_union(&upload, &surface->prev_damage, damage); - ret = rpi_resource_update(surface->back, buffer, &upload, - &surface->surface->opaque); - pixman_region32_fini(&upload); - } - - pixman_region32_copy(&surface->prev_damage, damage); - surface->need_swap = 1; - - return ret; -} - -static struct rpir_view * -rpir_view_create(struct rpir_surface *surface) -{ - struct rpir_view *view; - - view = zalloc(sizeof *view); - if (view == NULL) - return NULL; - - view->surface = surface; - wl_list_insert(&surface->views, &view->surface_link); - - wl_list_init(&view->link); - view->handle = DISPMANX_NO_HANDLE; - - return view; -} - -static void -rpir_view_destroy(struct rpir_view *view) -{ - wl_list_remove(&view->link); - - if (view->handle != DISPMANX_NO_HANDLE) { - view->surface->visible_views--; - weston_log("ERROR rpi: destroying on-screen element\n"); - } - - if (view->view) - view->view->renderer_state = NULL; - - wl_list_remove(&view->surface_link); - if (wl_list_empty(&view->surface->views) && view->surface->surface == NULL) - rpir_surface_destroy(view->surface); - - DBG("rpir_view %p destroyed (%d)\n", view, view->handle); - - free(view); -} - -static void -matrix_type_str(struct weston_matrix *matrix, char *buf, int len) -{ - static const char types[33] = "TSRO"; - unsigned mask = matrix->type; - int i = 0; - - while (mask && i < len - 1) { - if (mask & (1u << i)) - *buf++ = types[i]; - mask &= ~(1u << i); - i++; - } - *buf = '\0'; -} - -static void -log_print_matrix(struct weston_matrix *matrix) -{ - char typestr[6]; - float *d = matrix->d; - - matrix_type_str(matrix, typestr, sizeof typestr); - weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n", - d[0], d[4], d[8], d[12]); - weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n", - d[1], d[5], d[9], d[13]); - weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n", - d[2], d[6], d[10], d[14]); - weston_log_continue("%14.6e %14.6e %14.6e %14.6e type: %s\n", - d[3], d[7], d[11], d[15], typestr); -} - -static void -warn_bad_matrix(struct weston_matrix *total, struct weston_matrix *output, - struct weston_matrix *surface) -{ - static int n_warn; - char typestr[6]; - - if (n_warn++ == 10) - weston_log("%s: not showing more warnings\n", __func__); - - if (n_warn > 10) - return; - - weston_log("%s: warning: total transformation is not renderable:\n", - __func__); - log_print_matrix(total); - - matrix_type_str(surface, typestr, sizeof typestr); - weston_log_continue("surface matrix type: %s\n", typestr); - matrix_type_str(output, typestr, sizeof typestr); - weston_log_continue("output matrix type: %s\n", typestr); -} - -/*#define SURFACE_TRANSFORM */ - -static int -rpir_view_compute_rects(struct rpir_view *view, - VC_RECT_T *src_rect, VC_RECT_T *dst_rect, - VC_IMAGE_TRANSFORM_T *flipmask) -{ - struct weston_output *output_base = view->view->surface->output; - struct weston_matrix matrix = view->view->transform.matrix; - VC_IMAGE_TRANSFORM_T flipt = 0; - int src_x, src_y; - int dst_x, dst_y; - int src_width, src_height; - int dst_width, dst_height; - struct weston_vector p1 = {{ 0.0f, 0.0f, 0.0f, 1.0f }}; - struct weston_vector p2 = {{ 0.0f, 0.0f, 0.0f, 1.0f }}; - int t; - int over; - - /* XXX: take buffer transform into account */ - - /* src is in 16.16, dst is in 32.0 fixed point. - * Negative values are not allowed in VC_RECT_T. - * Clip size to output boundaries, firmware ignores - * huge elements like 8192x8192. - */ - - src_x = 0 << 16; - src_y = 0 << 16; - - if (view->surface->buffer_type == BUFFER_TYPE_EGL) { - struct weston_buffer *buffer = - view->surface->egl_front->buffer_ref.buffer; - - if (!buffer) - return -1; - - src_width = buffer->width << 16; - src_height = buffer->height << 16; - } else { - src_width = view->surface->front->width << 16; - src_height = view->surface->front->height << 16; - } - - weston_matrix_multiply(&matrix, &output_base->matrix); - -#ifdef SURFACE_TRANSFORM - if (matrix.type >= WESTON_MATRIX_TRANSFORM_OTHER) { -#else - if (matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE) { -#endif - warn_bad_matrix(&matrix, &output_base->matrix, - &view->view->transform.matrix); - } else { - if (matrix.type & WESTON_MATRIX_TRANSFORM_ROTATE) { - if (fabsf(matrix.d[0]) < 1e-4f && - fabsf(matrix.d[5]) < 1e-4f) { - flipt |= TRANSFORM_TRANSPOSE; - } else if (fabsf(matrix.d[1]) < 1e-4 && - fabsf(matrix.d[4]) < 1e-4) { - /* no transpose */ - } else { - warn_bad_matrix(&matrix, &output_base->matrix, - &view->view->transform.matrix); - } - } - } - - p2.f[0] = view->view->surface->width; - p2.f[1] = view->view->surface->height; - - /* transform top-left and bot-right corner into screen coordinates */ - weston_matrix_transform(&matrix, &p1); - weston_matrix_transform(&matrix, &p2); - - /* Compute the destination rectangle on screen, converting - * negative dimensions to flips. - */ - - dst_width = round(p2.f[0] - p1.f[0]); - if (dst_width < 0) { - dst_x = round(p2.f[0]); - dst_width = -dst_width; - - if (!(flipt & TRANSFORM_TRANSPOSE)) - flipt |= TRANSFORM_HFLIP; - else - flipt |= TRANSFORM_VFLIP; - } else { - dst_x = round(p1.f[0]); - } - - dst_height = round(p2.f[1] - p1.f[1]); - if (dst_height < 0) { - dst_y = round(p2.f[1]); - dst_height = -dst_height; - - if (!(flipt & TRANSFORM_TRANSPOSE)) - flipt |= TRANSFORM_VFLIP; - else - flipt |= TRANSFORM_HFLIP; - } else { - dst_y = round(p1.f[1]); - } - - if (dst_width == 0 || dst_height == 0) { - DBG("ignored, zero surface area before clipping\n"); - return -1; - } - -#ifdef SURFACE_TRANSFORM - /* Dispmanx works as if you flipped the whole screen, when - * you flip an element. But, we want to flip an element in place. - * XXX: fixme - */ - if (flipt & TRANSFORM_HFLIP) - dst_x = output_base->width - dst_x; - if (flipt & TRANSFORM_VFLIP) - dst_y = output_base->height - dst_y; - if (flipt & TRANSFORM_TRANSPOSE) { - int_swap(&dst_x, &dst_y); - int_swap(&dst_width, &dst_height); - } -#else - switch (output_base->transform) { - case WL_OUTPUT_TRANSFORM_FLIPPED: - flipt = TRANSFORM_HFLIP; - break; - case WL_OUTPUT_TRANSFORM_NORMAL: - flipt = 0; - break; - - case WL_OUTPUT_TRANSFORM_FLIPPED_90: - flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE; - break; - case WL_OUTPUT_TRANSFORM_90: - flipt = TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_180: - flipt = TRANSFORM_VFLIP; - break; - case WL_OUTPUT_TRANSFORM_180: - flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP; - break; - - case WL_OUTPUT_TRANSFORM_FLIPPED_270: - flipt = TRANSFORM_TRANSPOSE; - break; - case WL_OUTPUT_TRANSFORM_270: - flipt = TRANSFORM_HFLIP | TRANSFORM_TRANSPOSE; - break; - default: - break; - } -#endif - - /* clip destination rectangle to screen dimensions */ - - if (dst_x < 0) { - t = (int64_t)dst_x * src_width / dst_width; - src_width += t; - dst_width += dst_x; - src_x -= t; - dst_x = 0; - } - - if (dst_y < 0) { - t = (int64_t)dst_y * src_height / dst_height; - src_height += t; - dst_height += dst_y; - src_y -= t; - dst_y = 0; - } - - over = dst_x + dst_width - output_base->width; - if (over > 0) { - t = (int64_t)over * src_width / dst_width; - src_width -= t; - dst_width -= over; - } - - over = dst_y + dst_height - output_base->height; - if (over > 0) { - t = (int64_t)over * src_height / dst_height; - src_height -= t; - dst_height -= over; - } - - src_width = int_max(src_width, 0); - src_height = int_max(src_height, 0); - - DBG("rpir_view %p %dx%d: p1 %f, %f; p2 %f, %f\n", view, - view->view->surface->width, - view->view->surface->height, - p1.f[0], p1.f[1], p2.f[0], p2.f[1]); - DBG("src rect %d;%d, %d;%d, %d;%dx%d;%d\n", - src_x >> 16, src_x & 0xffff, - src_y >> 16, src_y & 0xffff, - src_width >> 16, src_width & 0xffff, - src_height >> 16, src_height & 0xffff); - DBG("dest rect %d, %d, %dx%d%s%s%s\n", - dst_x, dst_y, dst_width, dst_height, - (flipt & TRANSFORM_HFLIP) ? " hflip" : "", - (flipt & TRANSFORM_VFLIP) ? " vflip" : "", - (flipt & TRANSFORM_TRANSPOSE) ? " transp" : ""); - - assert(src_x >= 0); - assert(src_y >= 0); - assert(dst_x >= 0); - assert(dst_y >= 0); - - if (dst_width < 1 || dst_height < 1) { - DBG("ignored, zero surface area after clipping\n"); - return -1; - } - - /* EGL buffers will be upside-down related to what DispmanX expects */ - if (view->surface->buffer_type == BUFFER_TYPE_EGL) - flipt ^= TRANSFORM_VFLIP; - - vc_dispmanx_rect_set(src_rect, src_x, src_y, src_width, src_height); - vc_dispmanx_rect_set(dst_rect, dst_x, dst_y, dst_width, dst_height); - *flipmask = flipt; - - return 0; -} - -static DISPMANX_TRANSFORM_T -vc_image2dispmanx_transform(VC_IMAGE_TRANSFORM_T t) -{ - /* XXX: uhh, are these right? */ - switch (t) { - case VC_IMAGE_ROT0: - return DISPMANX_NO_ROTATE; - case VC_IMAGE_MIRROR_ROT0: - return DISPMANX_FLIP_HRIZ; - case VC_IMAGE_MIRROR_ROT180: - return DISPMANX_FLIP_VERT; - case VC_IMAGE_ROT180: - return DISPMANX_ROTATE_180; - case VC_IMAGE_MIRROR_ROT90: - return DISPMANX_ROTATE_90 | DISPMANX_FLIP_HRIZ; - case VC_IMAGE_ROT270: - return DISPMANX_ROTATE_270; - case VC_IMAGE_ROT90: - return DISPMANX_ROTATE_90; - case VC_IMAGE_MIRROR_ROT270: - return DISPMANX_ROTATE_270 | DISPMANX_FLIP_VERT; - default: - assert(0 && "bad VC_IMAGE_TRANSFORM_T"); - return DISPMANX_NO_ROTATE; - } -} - -static DISPMANX_RESOURCE_HANDLE_T -rpir_surface_get_resource(struct rpir_surface *surface) -{ - switch (surface->buffer_type) { - case BUFFER_TYPE_SHM: - case BUFFER_TYPE_NULL: - return surface->front->handle; - case BUFFER_TYPE_EGL: - if (surface->egl_front != NULL) - return surface->egl_front->resource_handle; - default: - return DISPMANX_NO_HANDLE; - } -} - -#ifdef HAVE_ELEMENT_SET_OPAQUE_RECT -static int -rpir_surface_set_opaque_rect(struct rpir_surface *surface, - DISPMANX_UPDATE_HANDLE_T update) -{ - int ret; - - if (pixman_region32_not_empty(&surface->surface->opaque) && - surface->opaque_regions) { - pixman_box32_t *box; - VC_RECT_T opaque_rect; - - box = pixman_region32_extents(&surface->surface->opaque); - opaque_rect.x = box->x1; - opaque_rect.y = box->y1; - opaque_rect.width = box->x2 - box->x1; - opaque_rect.height = box->y2 - box->y1; - - ret = vc_dispmanx_element_set_opaque_rect(update, - surface->handle, - &opaque_rect); - if (ret) { - weston_log("vc_dispmanx_element_set_opaque_rect failed\n"); - return -1; - } - } - - return 0; -} -#endif - -static int -rpir_view_dmx_add(struct rpir_view *view, struct rpir_output *output, - DISPMANX_UPDATE_HANDLE_T update, int layer) -{ - /* Do not use DISPMANX_FLAGS_ALPHA_PREMULT here. - * If you define PREMULT and ALPHA_MIX, the hardware will not - * multiply the source color with the element alpha, leading to - * bad colors. Instead, we define PREMULT during pixel data upload. - */ - VC_DISPMANX_ALPHA_T alphasetup = { - DISPMANX_FLAGS_ALPHA_FROM_SOURCE | - DISPMANX_FLAGS_ALPHA_MIX, - float2uint8(view->view->alpha), /* opacity 0-255 */ - 0 /* mask resource handle */ - }; - VC_RECT_T dst_rect; - VC_RECT_T src_rect; - VC_IMAGE_TRANSFORM_T flipmask; - int ret; - DISPMANX_RESOURCE_HANDLE_T resource_handle; - - resource_handle = rpir_surface_get_resource(view->surface); - if (resource_handle == DISPMANX_NO_HANDLE) { - weston_log("%s: no buffer yet, aborting\n", __func__); - return 0; - } - - ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask); - if (ret < 0) - return 0; - - view->handle = vc_dispmanx_element_add( - update, - output->display, - layer, - &dst_rect, - resource_handle, - &src_rect, - DISPMANX_PROTECTION_NONE, - &alphasetup, - NULL /* clamp */, - vc_image2dispmanx_transform(flipmask)); - DBG("rpir_surface %p add %u, alpha %f resource %d\n", view, - view->handle, view->view->alpha, resource_handle); - - if (view->handle == DISPMANX_NO_HANDLE) - return -1; - -#ifdef HAVE_ELEMENT_SET_OPAQUE_RECT - ret = rpir_surface_set_opaque_rect(surface, update); - if (ret < 0) - return -1; -#endif - - view->surface->visible_views++; - - return 1; -} - -static void -rpir_view_dmx_swap(struct rpir_view *view, - DISPMANX_UPDATE_HANDLE_T update) -{ - VC_RECT_T rect; - pixman_box32_t *r; - - /* XXX: skip, iff resource was not reallocated, and single-buffering */ - vc_dispmanx_element_change_source(update, view->handle, - view->surface->front->handle); - - /* This is current damage now, after rpir_surface_damage() */ - r = pixman_region32_extents(&view->surface->prev_damage); - - vc_dispmanx_rect_set(&rect, r->x1, r->y1, - r->x2 - r->x1, r->y2 - r->y1); - vc_dispmanx_element_modified(update, view->handle, &rect); - DBG("rpir_view %p swap\n", view); -} - -static int -rpir_view_dmx_move(struct rpir_view *view, - DISPMANX_UPDATE_HANDLE_T update, int layer) -{ - uint8_t alpha = float2uint8(view->view->alpha); - VC_RECT_T dst_rect; - VC_RECT_T src_rect; - VC_IMAGE_TRANSFORM_T flipmask; - int ret; - - /* XXX: return early, if all attributes stay the same */ - - if (view->surface->buffer_type == BUFFER_TYPE_EGL) { - DISPMANX_RESOURCE_HANDLE_T resource_handle; - - resource_handle = rpir_surface_get_resource(view->surface); - if (resource_handle == DISPMANX_NO_HANDLE) { - weston_log("%s: no buffer yet, aborting\n", __func__); - return 0; - } - - vc_dispmanx_element_change_source(update, - view->handle, - resource_handle); - } - - ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask); - if (ret < 0) - return 0; - - ret = vc_dispmanx_element_change_attributes( - update, - view->handle, - ELEMENT_CHANGE_LAYER | - ELEMENT_CHANGE_OPACITY | - ELEMENT_CHANGE_TRANSFORM | - ELEMENT_CHANGE_DEST_RECT | - ELEMENT_CHANGE_SRC_RECT, - layer, - alpha, - &dst_rect, - &src_rect, - DISPMANX_NO_HANDLE, - /* This really is DISPMANX_TRANSFORM_T, no matter - * what the header says. */ - vc_image2dispmanx_transform(flipmask)); - DBG("rpir_view %p move\n", view); - - if (ret) - return -1; - -#ifdef HAVE_ELEMENT_SET_OPAQUE_RECT - ret = rpir_surface_set_opaque_rect(surface, update); - if (ret < 0) - return -1; -#endif - - return 1; -} - -static void -rpir_view_dmx_remove(struct rpir_view *view, - DISPMANX_UPDATE_HANDLE_T update) -{ - if (view->handle == DISPMANX_NO_HANDLE) - return; - - vc_dispmanx_element_remove(update, view->handle); - DBG("rpir_view %p remove %u\n", view, view->handle); - view->handle = DISPMANX_NO_HANDLE; - view->surface->visible_views--; -} - -static void -rpir_surface_swap_pointers(struct rpir_surface *surface) -{ - struct rpi_resource *tmp; - - if (surface->buffer_type == BUFFER_TYPE_EGL) { - if (surface->egl_back != NULL) { - assert(surface->egl_old_front == NULL); - surface->egl_old_front = surface->egl_front; - surface->egl_front = surface->egl_back; - surface->egl_back = NULL; - DBG("new front %d\n", surface->egl_front->resource_handle); - } - } else { - tmp = surface->front; - surface->front = surface->back; - surface->back = tmp; - DBG("new back %p, new front %p\n", surface->back, surface->front); - } -} - -static int -is_view_not_visible(struct weston_view *view) -{ - /* Return true, if surface is guaranteed to be totally obscured. */ - int ret; - pixman_region32_t unocc; - - pixman_region32_init(&unocc); - pixman_region32_subtract(&unocc, &view->transform.boundingbox, - &view->clip); - ret = !pixman_region32_not_empty(&unocc); - pixman_region32_fini(&unocc); - - return ret; -} - -static void -rpir_view_update(struct rpir_view *view, struct rpir_output *output, - DISPMANX_UPDATE_HANDLE_T update, int layer) -{ - int ret; - int obscured; - - obscured = is_view_not_visible(view->view); - if (obscured) { - DBG("rpir_view %p totally obscured.\n", view); - - wl_list_remove(&view->link); - if (view->handle == DISPMANX_NO_HANDLE) { - wl_list_init(&view->link); - } else { - rpir_view_dmx_remove(view, update); - wl_list_insert(&output->view_cleanup_list, - &view->link); - } - - goto out; - } - - if (view->handle == DISPMANX_NO_HANDLE) { - ret = rpir_view_dmx_add(view, output, update, layer); - if (ret == 0) { - wl_list_remove(&view->link); - wl_list_init(&view->link); - } else if (ret < 0) { - weston_log("ERROR rpir_view_dmx_add() failed.\n"); - } - } else { - if (view->surface->need_swap) - rpir_view_dmx_swap(view, update); - - ret = rpir_view_dmx_move(view, update, layer); - if (ret == 0) { - rpir_view_dmx_remove(view, update); - - wl_list_remove(&view->link); - wl_list_insert(&output->view_cleanup_list, - &view->link); - } else if (ret < 0) { - weston_log("ERROR rpir_view_dmx_move() failed.\n"); - } - } - -out: - view->layer = layer; -} - -static int -rpi_renderer_read_pixels(struct weston_output *base, - pixman_format_code_t format, void *pixels, - uint32_t x, uint32_t y, - uint32_t width, uint32_t height) -{ - struct rpir_output *output = to_rpir_output(base); - struct rpi_resource *buffer = &output->capture_buffer; - VC_RECT_T rect; - uint32_t fb_width, fb_height; - uint32_t dst_pitch; - uint32_t i; - int ret; - - fb_width = base->current_mode->width; - fb_height = base->current_mode->height; - - DBG("%s(%u, %u, %u, %u), resource %p\n", __func__, - x, y, width, height, buffer); - - if (format != PIXMAN_a8r8g8b8) { - weston_log("rpi-renderer error: bad read_format\n"); - return -1; - } - - dst_pitch = fb_width * 4; - - if (buffer->handle == DISPMANX_NO_HANDLE) { - free(output->capture_data); - output->capture_data = NULL; - - ret = rpi_resource_realloc(buffer, VC_IMAGE_ARGB8888, - fb_width, fb_height, - dst_pitch, fb_height); - if (ret < 0) { - weston_log("rpi-renderer error: " - "allocating read buffer failed\n"); - return -1; - } - - ret = vc_dispmanx_snapshot(output->display, buffer->handle, - VC_IMAGE_ROT0); - if (ret) { - weston_log("rpi-renderer error: " - "vc_dispmanx_snapshot returned %d\n", ret); - return -1; - } - DBG("%s: snapshot done.\n", __func__); - } - - /* - * If vc_dispmanx_resource_read_data was able to read sub-rectangles, - * we could read directly into 'pixels'. But it cannot, it does not - * use rect.x or rect.width, and does this: - * host_start = (uint8_t *)dst_address + (dst_pitch * p_rect->y); - * In other words, it is only good for reading the full buffer in - * one go. - */ - vc_dispmanx_rect_set(&rect, 0, 0, fb_width, fb_height); - - if (x == 0 && y == 0 && width == fb_width && height == fb_height) { - ret = vc_dispmanx_resource_read_data(buffer->handle, &rect, - pixels, dst_pitch); - if (ret) { - weston_log("rpi-renderer error: " - "resource_read_data returned %d\n", ret); - return -1; - } - DBG("%s: full frame done.\n", __func__); - return 0; - } - - if (!output->capture_data) { - output->capture_data = malloc(fb_height * dst_pitch); - if (!output->capture_data) { - weston_log("rpi-renderer error: " - "out of memory\n"); - return -1; - } - - ret = vc_dispmanx_resource_read_data(buffer->handle, &rect, - output->capture_data, - dst_pitch); - if (ret) { - weston_log("rpi-renderer error: " - "resource_read_data returned %d\n", ret); - return -1; - } - } - - for (i = 0; i < height; i++) { - uint8_t *src = output->capture_data + - (y + i) * dst_pitch + x * 4; - uint8_t *dst = (uint8_t *)pixels + i * width * 4; - memcpy(dst, src, width * 4); - } - - return 0; -} - -static void -rpir_output_dmx_remove_all(struct rpir_output *output, - DISPMANX_UPDATE_HANDLE_T update) -{ - struct rpir_view *view; - - while (!wl_list_empty(&output->view_list)) { - view = container_of(output->view_list.next, - struct rpir_view, link); - rpir_view_dmx_remove(view, update); - - wl_list_remove(&view->link); - wl_list_insert(&output->view_cleanup_list, &view->link); - } -} - -/* Note: this won't work right for multiple outputs. A DispmanX Element - * is tied to one DispmanX Display, i.e. output. - */ -static void -rpi_renderer_repaint_output(struct weston_output *base, - pixman_region32_t *output_damage) -{ - struct weston_compositor *compositor = base->compositor; - struct rpir_output *output = to_rpir_output(base); - struct weston_view *wv; - struct rpir_view *view; - struct wl_list done_list; - int layer = 1; - - assert(output->update != DISPMANX_NO_HANDLE); - - rpi_resource_release(&output->capture_buffer); - free(output->capture_data); - output->capture_data = NULL; - - /* Swap resources on surfaces as needed */ - wl_list_for_each_reverse(wv, &compositor->view_list, link) - wv->surface->touched = false; - - wl_list_for_each_reverse(wv, &compositor->view_list, link) { - view = to_rpir_view(wv); - - if (!wv->surface->touched) { - wv->surface->touched = true; - - if (view->surface->buffer_type == BUFFER_TYPE_EGL || - view->surface->need_swap) - rpir_surface_swap_pointers(view->surface); - } - - if (view->surface->buffer_type == BUFFER_TYPE_EGL) { - struct weston_buffer *buffer; - buffer = view->surface->egl_front->buffer_ref.buffer; - if (buffer != NULL) { - rpi_buffer_egl_lock(buffer); - } else { - weston_log("warning: client destroyed current front buffer\n"); - - wl_list_remove(&view->link); - if (view->handle == DISPMANX_NO_HANDLE) { - wl_list_init(&view->link); - } else { - rpir_view_dmx_remove(view, output->update); - wl_list_insert(&output->view_cleanup_list, - &view->link); - } - } - } - } - - /* update all renderable surfaces */ - wl_list_init(&done_list); - wl_list_for_each_reverse(wv, &compositor->view_list, link) { - if (wv->plane != &compositor->primary_plane) - continue; - - view = to_rpir_view(wv); - assert(!wl_list_empty(&view->link) || - view->handle == DISPMANX_NO_HANDLE); - - wl_list_remove(&view->link); - wl_list_insert(&done_list, &view->link); - rpir_view_update(view, output, output->update, layer++); - } - - /* Mark all surfaces as swapped */ - wl_list_for_each_reverse(wv, &compositor->view_list, link) - to_rpir_surface(wv->surface)->need_swap = 0; - - /* Remove all surfaces that are still on screen, but were - * not rendered this time. - */ - rpir_output_dmx_remove_all(output, output->update); - - wl_list_insert_list(&output->view_list, &done_list); - output->update = DISPMANX_NO_HANDLE; - - /* The frame_signal is emitted in rpi_renderer_finish_frame(), - * so that the firmware can capture the up-to-date contents. - */ - pixman_region32_copy(&base->previous_damage, output_damage); -} - -static void -rpi_renderer_flush_damage(struct weston_surface *base) -{ - /* Called for every surface just before repainting it, if - * having an shm buffer. - */ - struct rpir_surface *surface = to_rpir_surface(base); - struct weston_buffer *buffer = surface->buffer_ref.buffer; - int ret; - - assert(buffer); - assert(wl_shm_buffer_get(buffer->resource)); - - ret = rpir_surface_damage(surface, buffer, &base->damage); - if (ret) - weston_log("%s error: updating Dispmanx resource failed.\n", - __func__); - - weston_buffer_reference(&surface->buffer_ref, NULL); -} - -static void -rpi_renderer_attach(struct weston_surface *base, struct weston_buffer *buffer) -{ - /* Called every time a client commits an attach. */ - struct rpir_surface *surface = to_rpir_surface(base); - - assert(surface); - if (!surface) - return; - - if (surface->buffer_type == BUFFER_TYPE_SHM) { - if (!surface->single_buffer) - /* XXX: need to check if in middle of update */ - rpi_resource_release(surface->back); - - if (!surface->visible_views) - /* XXX: cannot do this, if middle of an update */ - rpi_resource_release(surface->front); - - weston_buffer_reference(&surface->buffer_ref, NULL); - } - - /* If buffer is NULL, Weston core unmaps the surface, the surface - * will not appear in repaint list, and so rpi_renderer_repaint_output - * will remove the DispmanX element. Later, for SHM, also the front - * buffer will be released in the cleanup_list processing. - */ - if (!buffer) - return; - - if (wl_shm_buffer_get(buffer->resource)) { - surface->buffer_type = BUFFER_TYPE_SHM; - buffer->shm_buffer = wl_shm_buffer_get(buffer->resource); - buffer->width = wl_shm_buffer_get_width(buffer->shm_buffer); - buffer->height = wl_shm_buffer_get_height(buffer->shm_buffer); - - weston_buffer_reference(&surface->buffer_ref, buffer); - } else { -#if ENABLE_EGL - struct rpi_renderer *renderer = to_rpi_renderer(base->compositor); - struct wl_resource *wl_resource = buffer->resource; - - if (!renderer->has_bind_display || - !renderer->query_buffer(renderer->egl_display, - wl_resource, - EGL_WIDTH, &buffer->width)) { - weston_log("unhandled buffer type!\n"); - weston_buffer_reference(&surface->buffer_ref, NULL); - surface->buffer_type = BUFFER_TYPE_NULL; - } - - renderer->query_buffer(renderer->egl_display, - wl_resource, - EGL_HEIGHT, &buffer->height); - - surface->buffer_type = BUFFER_TYPE_EGL; - - if (surface->egl_back == NULL) - surface->egl_back = zalloc(sizeof *surface->egl_back); - - weston_buffer_reference(&surface->egl_back->buffer_ref, buffer); - surface->egl_back->resource_handle = - vc_dispmanx_get_handle_from_wl_buffer(wl_resource); -#else - weston_log("unhandled buffer type!\n"); - weston_buffer_reference(&surface->buffer_ref, NULL); - surface->buffer_type = BUFFER_TYPE_NULL; -#endif - } -} - -static void -rpir_surface_handle_surface_destroy(struct wl_listener *listener, void *data) -{ - struct rpir_surface *surface; - struct weston_surface *base = data; - - surface = container_of(listener, struct rpir_surface, - surface_destroy_listener); - - assert(surface); - assert(surface->surface == base); - if (!surface) - return; - - surface->surface = NULL; - base->renderer_state = NULL; - - if (wl_list_empty(&surface->views)) - rpir_surface_destroy(surface); -} - -static int -rpi_renderer_create_surface(struct weston_surface *base) -{ - struct rpi_renderer *renderer = to_rpi_renderer(base->compositor); - struct rpir_surface *surface; - - assert(base->renderer_state == NULL); - - surface = rpir_surface_create(renderer); - if (!surface) - return -1; - - surface->surface = base; - base->renderer_state = surface; - - surface->surface_destroy_listener.notify = - rpir_surface_handle_surface_destroy; - wl_signal_add(&base->destroy_signal, - &surface->surface_destroy_listener); - - return 0; -} - -static int -rpi_renderer_create_view(struct weston_view *base) -{ - struct rpir_surface *surface = to_rpir_surface(base->surface); - struct rpir_view *view; - - assert(base->renderer_state == NULL); - - view = rpir_view_create(surface); - if (!view) - return -1; - - view->view = base; - base->renderer_state = view; - - view->view_destroy_listener.notify = - rpir_view_handle_view_destroy; - wl_signal_add(&base->destroy_signal, - &view->view_destroy_listener); - - return 0; -} - -static void -rpi_renderer_surface_set_color(struct weston_surface *base, - float red, float green, float blue, float alpha) -{ - struct rpir_surface *surface = to_rpir_surface(base); - uint8_t color[4]; - VC_RECT_T rect; - int ret; - - assert(surface); - - ret = rpi_resource_realloc(surface->back, VC_IMAGE_ARGB8888, - 1, 1, 4, 1); - if (ret < 0) { - weston_log("Error: %s: rpi_resource_realloc failed.\n", - __func__); - return; - } - - color[0] = float2uint8(blue); - color[1] = float2uint8(green); - color[2] = float2uint8(red); - color[3] = float2uint8(alpha); - - vc_dispmanx_rect_set(&rect, 0, 0, 1, 1); - ret = vc_dispmanx_resource_write_data(surface->back->handle, - VC_IMAGE_ARGB8888, - 4, color, &rect); - if (ret) { - weston_log("Error: %s: resource_write_data failed.\n", - __func__); - return; - } - - DBG("%s: resource %p solid color BGRA %u,%u,%u,%u\n", __func__, - surface->back, color[0], color[1], color[2], color[3]); - - /*pixman_region32_copy(&surface->prev_damage, damage);*/ - surface->need_swap = 1; -} - -static void -rpir_view_handle_view_destroy(struct wl_listener *listener, void *data) -{ - struct rpir_view *view; - struct weston_view *base = data; - - view = container_of(listener, struct rpir_view, view_destroy_listener); - - assert(view); - assert(view->view == base); - if (!view) - return; - - view->view = NULL; - base->renderer_state = NULL; - - /* If guaranteed to not be on screen, just destroy it. */ - if (wl_list_empty(&view->link)) - rpir_view_destroy(view); - - /* Otherwise, the view is either on screen and needs - * to be removed by a repaint update, or it is in the - * view_cleanup_list, and will be destroyed by - * rpi_renderer_finish_frame(). - */ -} - -static void -rpi_renderer_destroy(struct weston_compositor *compositor) -{ - struct rpi_renderer *renderer = to_rpi_renderer(compositor); - -#if ENABLE_EGL - if (renderer->has_bind_display) - renderer->unbind_display(renderer->egl_display, - compositor->wl_display); -#endif - - free(renderer); - compositor->renderer = NULL; -} - -WL_EXPORT int -rpi_renderer_create(struct weston_compositor *compositor, - const struct rpi_renderer_parameters *params) -{ - struct rpi_renderer *renderer; -#if ENABLE_EGL - const char *extensions; - EGLBoolean ret; - EGLint major, minor; -#endif - - weston_log("Initializing the DispmanX compositing renderer\n"); - - renderer = zalloc(sizeof *renderer); - if (renderer == NULL) - return -1; - - renderer->single_buffer = params->single_buffer; - renderer->enable_opaque_regions = params->opaque_regions; - - renderer->base.read_pixels = rpi_renderer_read_pixels; - renderer->base.repaint_output = rpi_renderer_repaint_output; - renderer->base.flush_damage = rpi_renderer_flush_damage; - renderer->base.attach = rpi_renderer_attach; - renderer->base.surface_set_color = rpi_renderer_surface_set_color; - renderer->base.destroy = rpi_renderer_destroy; - -#ifdef ENABLE_EGL - renderer->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (renderer->egl_display == EGL_NO_DISPLAY) { - weston_log("failed to create EGL display\n"); - free(renderer); - return -1; - } - - if (!eglInitialize(renderer->egl_display, &major, &minor)) { - weston_log("failed to initialize EGL display\n"); - free(renderer); - return -1; - } - - renderer->bind_display = - (void *) eglGetProcAddress("eglBindWaylandDisplayWL"); - renderer->unbind_display = - (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL"); - renderer->query_buffer = - (void *) eglGetProcAddress("eglQueryWaylandBufferWL"); - - extensions = (const char *) eglQueryString(renderer->egl_display, - EGL_EXTENSIONS); - if (!extensions) { - weston_log("Retrieving EGL extension string failed.\n"); - eglTerminate(renderer->egl_display); - free(renderer); - return -1; - } - - if (strstr(extensions, "EGL_WL_bind_wayland_display")) - renderer->has_bind_display = 1; - - if (renderer->has_bind_display) { - ret = renderer->bind_display(renderer->egl_display, - compositor->wl_display); - if (!ret) - renderer->has_bind_display = 0; - } -#endif - - compositor->renderer = &renderer->base; - compositor->read_format = PIXMAN_a8r8g8b8; - /* WESTON_CAP_ROTATION_ANY not supported */ - - wl_display_add_shm_format(compositor->wl_display, WL_SHM_FORMAT_RGB565); - - return 0; -} - -WL_EXPORT int -rpi_renderer_output_create(struct weston_output *base, - DISPMANX_DISPLAY_HANDLE_T display) -{ - struct rpir_output *output; - - assert(base->renderer_state == NULL); - - output = zalloc(sizeof *output); - if (output == NULL) - return -1; - - output->display = display; - output->update = DISPMANX_NO_HANDLE; - wl_list_init(&output->view_list); - wl_list_init(&output->view_cleanup_list); - rpi_resource_init(&output->capture_buffer); - base->renderer_state = output; - - return 0; -} - -WL_EXPORT void -rpi_renderer_output_destroy(struct weston_output *base) -{ - struct rpir_output *output = to_rpir_output(base); - struct rpir_view *view; - DISPMANX_UPDATE_HANDLE_T update; - - rpi_resource_release(&output->capture_buffer); - free(output->capture_data); - output->capture_data = NULL; - - update = vc_dispmanx_update_start(0); - rpir_output_dmx_remove_all(output, update); - vc_dispmanx_update_submit_sync(update); - - while (!wl_list_empty(&output->view_cleanup_list)) { - view = container_of(output->view_cleanup_list.next, - struct rpir_view, link); - rpir_view_destroy(view); - } - - free(output); - base->renderer_state = NULL; -} - -WL_EXPORT void -rpi_renderer_set_update_handle(struct weston_output *base, - DISPMANX_UPDATE_HANDLE_T handle) -{ - struct rpir_output *output = to_rpir_output(base); - - output->update = handle; -} - -WL_EXPORT void -rpi_renderer_finish_frame(struct weston_output *base) -{ - struct rpir_output *output = to_rpir_output(base); - struct weston_compositor *compositor = base->compositor; - struct weston_view *wv; - struct rpir_view *view; - - while (!wl_list_empty(&output->view_cleanup_list)) { - view = container_of(output->view_cleanup_list.next, - struct rpir_view, link); - - if (view->view) { - /* The weston_view still exists, but is - * temporarily not visible, and hence its Element - * was removed. The current front buffer contents - * must be preserved. - */ - if (!view->surface->visible_views) - rpi_resource_release(view->surface->back); - - wl_list_remove(&view->link); - wl_list_init(&view->link); - } else { - rpir_view_destroy(view); - } - } - - wl_list_for_each(wv, &compositor->view_list, link) { - view = to_rpir_view(wv); - - if (view->surface->buffer_type != BUFFER_TYPE_EGL) - continue; - - rpir_egl_buffer_destroy(view->surface->egl_old_front); - view->surface->egl_old_front = NULL; - } - - wl_signal_emit(&base->frame_signal, base); -} diff --git a/src/rpi-renderer.h b/src/rpi-renderer.h deleted file mode 100644 index 63706826..00000000 --- a/src/rpi-renderer.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright © 2013 Raspberry Pi Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef RPI_RENDERER_H -#define RPI_RENDERER_H - -struct rpi_renderer_parameters { - int single_buffer; - int opaque_regions; -}; - -int -rpi_renderer_create(struct weston_compositor *compositor, - const struct rpi_renderer_parameters *params); - -int -rpi_renderer_output_create(struct weston_output *base, - DISPMANX_DISPLAY_HANDLE_T display); - -void -rpi_renderer_output_destroy(struct weston_output *base); - -void -rpi_renderer_set_update_handle(struct weston_output *base, - DISPMANX_UPDATE_HANDLE_T handle); - -void -rpi_renderer_finish_frame(struct weston_output *base); - -#endif /* RPI_RENDERER_H */