Hello, This patch reuses the patchset sent by Olivier Blin on 17/07/06. It actually would replace the "3-3-rdp-backend.so-OpenGL-hardware-acceleration.patch". It adds support of ARGB8888 gbm-format for the output, reads just the damaged pixels and y-flips back the image for repaint.
--- {a => b}/compositor/main.c | 23 ++- {a => b}/configure.ac | 4 +- {a => b}/libweston/compositor-rdp.c | 361 +++++++++++++++++++++++++++++++++++- {a => b}/libweston/compositor-rdp.h | 24 +++ 4 files changed, 399 insertions(+), 13 deletions(-) diff --git a/compositor/main.c b/compositor/main.c index 1e82788..6a701dc 100644 --- a/compositor/main.c +++ b/compositor/main.c @@ -519,6 +519,7 @@ usage(int error_code) " --rdp4-key=FILE\tThe file containing the key for RDP4 encryption\n" " --rdp-tls-cert=FILE\tThe file containing the certificate for TLS encryption\n" " --rdp-tls-key=FILE\tThe file containing the private key for TLS encryption\n" + " --use-pixman\t\tUse the pixman (CPU) renderer\n" "\n"); #endif @@ -1217,11 +1218,14 @@ static void rdp_backend_output_configure(struct wl_listener *listener, void *data) { struct weston_output *output = data; + struct weston_config *wc = wet_get_config(output->compositor); struct wet_compositor *compositor = to_wet_compositor(output->compositor); struct wet_output_config *parsed_options = compositor->parsed_options; + struct weston_config_section *section; const struct weston_rdp_output_api *api = weston_rdp_output_get_api(output->compositor); int width = 640; int height = 480; + char *gbm_format = NULL; assert(parsed_options); @@ -1230,6 +1234,8 @@ rdp_backend_output_configure(struct wl_listener *listener, void *data) return; } + section = weston_config_get_section(wc, "output", "name", output->name); + if (parsed_options->width) width = parsed_options->width; @@ -1239,6 +1245,12 @@ rdp_backend_output_configure(struct wl_listener *listener, void *data) weston_output_set_scale(output, 1); weston_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL); + weston_config_section_get_string(section, + "gbm-format", &gbm_format, NULL); + + api->set_gbm_format(output, gbm_format); + free(gbm_format); + if (api->output_set_size(output, width, height) < 0) { weston_log("Cannot configure output \"%s\" using weston_rdp_output_api.\n", output->name); @@ -1261,6 +1273,7 @@ weston_rdp_backend_config_init(struct weston_rdp_backend_config *config) config->server_key = NULL; config->env_socket = 0; config->no_clients_resize = 0; + config->use_pixman = false; } static int @@ -1268,6 +1281,7 @@ load_rdp_backend(struct weston_compositor *c, int *argc, char *argv[], struct weston_config *wc) { struct weston_rdp_backend_config config = {{ 0, }}; + struct weston_config_section *section; int ret = 0; struct wet_output_config *parsed_options = wet_init_parsed_options(c); @@ -1285,11 +1299,17 @@ load_rdp_backend(struct weston_compositor *c, { WESTON_OPTION_BOOLEAN, "no-clients-resize", 0, &config.no_clients_resize }, { WESTON_OPTION_STRING, "rdp4-key", 0, &config.rdp_key }, { WESTON_OPTION_STRING, "rdp-tls-cert", 0, &config.server_cert }, - { WESTON_OPTION_STRING, "rdp-tls-key", 0, &config.server_key } + { WESTON_OPTION_STRING, "rdp-tls-key", 0, &config.server_key }, + { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &config.use_pixman } }; parse_options(rdp_options, ARRAY_LENGTH(rdp_options), argc, argv); + section = weston_config_get_section(wc, "core", NULL, NULL); + weston_config_section_get_string(section, + "gbm-format", &config.gbm_format, + NULL); + ret = weston_compositor_load_backend(c, WESTON_BACKEND_RDP, &config.base); @@ -1303,6 +1323,7 @@ out: free(config.rdp_key); free(config.server_cert); free(config.server_key); + free(config.gbm_format); return ret; } diff --git a/configure.ac b/configure.ac index ff39469..2255d9e 100644 --- a/configure.ac +++ b/configure.ac @@ -260,9 +260,9 @@ AM_CONDITIONAL([ENABLE_RDP_COMPOSITOR], [test x$enable_rdp_compositor = xyes]) if test x$enable_rdp_compositor = xyes; then AC_DEFINE([BUILD_RDP_COMPOSITOR], [1], [Build the RDP compositor]) - PKG_CHECK_MODULES(RDP_COMPOSITOR, [freerdp2 >= 2.0.0], + PKG_CHECK_MODULES(RDP_COMPOSITOR, [freerdp2 >= 2.0.0 libudev >= 136 gbm], [], - [PKG_CHECK_MODULES(RDP_COMPOSITOR, [freerdp >= 1.1.0],[])] + [PKG_CHECK_MODULES(RDP_COMPOSITOR, [freerdp >= 1.1.0 libudev >= 136 gbm],[])] ) SAVED_CPPFLAGS="$CPPFLAGS" diff --git a/libweston/compositor-rdp.c b/libweston/compositor-rdp.c index ee68e96..e584088 100644 --- a/libweston/compositor-rdp.c +++ b/libweston/compositor-rdp.c @@ -30,8 +30,14 @@ #include <stdlib.h> #include <string.h> #include <errno.h> +#include <dlfcn.h> +#include <fcntl.h> +#include <unistd.h> #include <linux/input.h> +#include <gbm.h> +#include <libudev.h> + #if HAVE_FREERDP_VERSION_H #include <freerdp/version.h> #else @@ -84,6 +90,7 @@ #include "shared/timespec-util.h" #include "compositor.h" #include "compositor-rdp.h" +#include "gl-renderer.h" #include "pixman-renderer.h" #define MAX_FREERDP_FDS 32 @@ -115,6 +122,13 @@ struct rdp_backend { char *rdp_key; int tls_enabled; int no_clients_resize; + + /* For GL rendering */ + struct udev *udev; + int drm_fd; + struct gbm_device *gbm; + uint32_t gbm_format; + int use_pixman; }; enum peer_item_flags { @@ -133,8 +147,16 @@ struct rdp_peers_item { struct rdp_output { struct weston_output base; struct wl_event_source *finish_frame_timer; + uint32_t gbm_format; + struct gbm_surface *gbm_surface; pixman_image_t *shadow_surface; + int format; + int stride; + int height; + uint32_t *tmpdata, *image; + uint32_t tmpdata_size; + struct wl_list peers; }; @@ -164,6 +186,8 @@ to_rdp_backend(struct weston_compositor *base) return container_of(base->backend, struct rdp_backend, base); } +static struct gl_renderer_interface *gl_renderer; + static void rdp_peer_refresh_rfx(pixman_region32_t *damage, pixman_image_t *image, freerdp_peer *peer) { @@ -365,12 +389,31 @@ rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage, { struct rdp_output *output = container_of(output_base, struct rdp_output, base); struct weston_compositor *ec = output->base.compositor; + struct rdp_backend *b = to_rdp_backend(ec); struct rdp_peers_item *outputPeer; - pixman_renderer_output_set_buffer(output_base, output->shadow_surface); + if (b->use_pixman) + pixman_renderer_output_set_buffer(output_base, output->shadow_surface); ec->renderer->repaint_output(&output->base, damage); if (pixman_region32_not_empty(damage)) { + if (!b->use_pixman) { + /* Performance: Only read pixels that were actually repainted by renderer->repaint_output. */ + int i, nrects; + int x, y, width, height; + pixman_box32_t *rect=pixman_region32_rectangles(damage, &nrects); + for (i=0; i<nrects; ++i) { + x = rect[i].x1; + y = rect[i].y1; + width = rect[i].x2 - x; + height = rect[i].y2 - y; + + // It's y-flipped + ec->renderer->read_pixels(output_base, output->format, output->tmpdata, x, output->height-rect[i].y2, width, height); + pixman_blt(output->tmpdata, output->image, -width, output->stride, 32, 32, 0, 1-height, x, y, width, height); + } + } + wl_list_for_each(outputPeer, &output->peers, link) { if ((outputPeer->flags & RDP_PEER_ACTIVATED) && (outputPeer->flags & RDP_PEER_OUTPUT_ENABLED)) @@ -427,9 +470,229 @@ ensure_matching_mode(struct weston_output *output, struct weston_mode *target) } static int +open_drm_device(struct udev *udev) +{ + struct udev_enumerate *e; + struct udev_list_entry *entry; + struct udev_device *device; + const char *path, *filename; + int fd; + + e = udev_enumerate_new(udev); + udev_enumerate_add_match_subsystem(e, "drm"); + udev_enumerate_add_match_sysname(e, "renderD[0-9]*"); + + udev_enumerate_scan_devices(e); + device = NULL; + udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) { + path = udev_list_entry_get_name(entry); + device = udev_device_new_from_syspath(udev, path); + if (device) { + filename = udev_device_get_devnode(device); + fd = open(filename, O_RDWR | O_CLOEXEC); + if (fd < 0) { + udev_device_unref(device); + continue; + } + + weston_log("using %s\n", filename); + udev_device_unref(device); + udev_enumerate_unref(e); + return fd; + } + } + + udev_enumerate_unref(e); + return -1; +} + +static struct gbm_device * +create_gbm_device(int fd) +{ + struct gbm_device *gbm; + + gl_renderer = weston_load_module("gl-renderer.so", + "gl_renderer_interface"); + if (!gl_renderer) + return NULL; + + /* GBM will load a dri driver, but even though they need symbols from + * libglapi, in some version of Mesa they are not linked to it. Since + * only the gl-renderer module links to it, the call above won't make + * these symbols globally available, and loading the DRI driver fails. + * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */ + dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL); + + gbm = gbm_create_device(fd); + + return gbm; +} + +/* When initializing EGL, if the preferred buffer format isn't available + * we may be able to substitute an ARGB format for an XRGB one. + * + * This returns 0 if substitution isn't possible, but 0 might be a + * legitimate format for other EGL platforms, so the caller is + * responsible for checking for 0 before calling gl_renderer->create(). + * + * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689 + * but it's entirely possible we'll see this again on other implementations. + */ +static int +fallback_format_for(uint32_t format) +{ + switch (format) { + case GBM_FORMAT_XRGB8888: + return GBM_FORMAT_ARGB8888; + case GBM_FORMAT_XRGB2101010: + return GBM_FORMAT_ARGB2101010; + default: + return 0; + } +} + +static int +rdp_backend_create_gl_renderer(struct rdp_backend *b) +{ + EGLint format[3] = { + b->gbm_format, + fallback_format_for(b->gbm_format), + 0, + }; + int n_formats = 2; + + if (format[1]) + n_formats = 3; + if (gl_renderer->display_create(b->compositor, + EGL_PLATFORM_GBM_KHR, + (void *)b->gbm, + NULL, + gl_renderer->opaque_attribs, + format, + n_formats) < 0) { + return -1; + } + + return 0; +} + +static int +init_egl(struct rdp_backend *b) +{ + b->gbm = create_gbm_device(b->drm_fd); + + if (!b->gbm) + return -1; + + if (rdp_backend_create_gl_renderer(b) < 0) { + gbm_device_destroy(b->gbm); + return -1; + } + + return 0; +} + +static int +init_pixman(struct rdp_backend *b) +{ + return pixman_renderer_init(b->compositor); +} + +static int +parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format) +{ + int ret = 0; + + if (s == NULL) + *gbm_format = default_value; + else if (strcmp(s, "xrgb8888") == 0) + *gbm_format = GBM_FORMAT_XRGB8888; + else if (strcmp(s, "argb8888") == 0) + *gbm_format = GBM_FORMAT_ARGB8888; + else if (strcmp(s, "rgb565") == 0) + *gbm_format = GBM_FORMAT_RGB565; + else if (strcmp(s, "xrgb2101010") == 0) + *gbm_format = GBM_FORMAT_XRGB2101010; + else { + weston_log("fatal: unrecognized pixel format: %s\n", s); + ret = -1; + } + + return ret; +} +/* Init output state that depends on gl or gbm */ +static int +rdp_output_init_egl(struct rdp_output *output, struct rdp_backend *b) +{ + EGLint format[2] = { + output->gbm_format, + fallback_format_for(output->gbm_format), + }; + int n_formats = 1; + + output->gbm_surface = gbm_surface_create(b->gbm, + output->base.current_mode->width, + output->base.current_mode->height, + format[0], + GBM_BO_USE_SCANOUT | + GBM_BO_USE_RENDERING); + if (!output->gbm_surface) { + weston_log("failed to create gbm surface\n"); + return -1; + } + + if (format[1]) + n_formats = 2; + if (gl_renderer->output_window_create(&output->base, + (EGLNativeWindowType)output->gbm_surface, + output->gbm_surface, + gl_renderer->opaque_attribs, + format, + n_formats) < 0) { + weston_log("failed to create gl renderer output state\n"); + gbm_surface_destroy(output->gbm_surface); + return -1; + } + + return 0; +} + +static void +rdp_output_fini_egl(struct rdp_output *output) +{ + gl_renderer->output_destroy(&output->base); + gbm_surface_destroy(output->gbm_surface); +} + +static int +rdp_get_image_size(struct rdp_output *output) +{ + uint32_t image_size=pixman_image_get_width(output->shadow_surface)*pixman_image_get_height(output->shadow_surface)*sizeof(uint32_t); + + if (output->tmpdata_size < image_size) { + free(output->tmpdata); + output->tmpdata = malloc(image_size); + if (output->tmpdata == NULL) { + output->tmpdata_size = 0; + errno = ENOMEM; + return -1; + } + + output->tmpdata_size = image_size; + output->stride = pixman_image_get_stride(output->shadow_surface) / sizeof(uint32_t); + output->format = pixman_image_get_format(output->shadow_surface); + output->height = pixman_image_get_height(output->shadow_surface); + output->image = pixman_image_get_data(output->shadow_surface); + } + + return 0; +} + +static int rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode) { struct rdp_output *rdpOutput = container_of(output, struct rdp_output, base); + struct rdp_backend *b = to_rdp_backend(output->compositor); struct rdp_peers_item *rdpPeer; rdpSettings *settings; pixman_image_t *new_shadow_buffer; @@ -449,8 +712,21 @@ rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode) output->current_mode = local_mode; output->current_mode->flags |= WL_OUTPUT_MODE_CURRENT; - pixman_renderer_output_destroy(output); - pixman_renderer_output_create(output); + if (b->use_pixman) { + pixman_renderer_output_destroy(output); + if (pixman_renderer_output_create(output) < 0) { + weston_log("failed to init output pixman state with " + "new mode\n"); + return -1; + } + } else { + rdp_output_fini_egl(rdpOutput); + if (rdp_output_init_egl(rdpOutput, b) < 0) { + weston_log("failed to init output egl state with " + "new mode"); + return -1; + } + } new_shadow_buffer = pixman_image_create_bits(PIXMAN_x8r8g8b8, target_mode->width, target_mode->height, 0, target_mode->width * 4); @@ -459,6 +735,10 @@ rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode) pixman_image_unref(rdpOutput->shadow_surface); rdpOutput->shadow_surface = new_shadow_buffer; + if (!b->use_pixman) { + if (rdp_get_image_size(rdpOutput) < 0) return -1; + } + wl_list_for_each(rdpPeer, &rdpOutput->peers, link) { settings = rdpPeer->peer->settings; if (settings->DesktopWidth == (UINT32)target_mode->width && @@ -517,6 +797,17 @@ rdp_output_set_size(struct weston_output *base, return 0; } +static void +rdp_output_set_gbm_format(struct weston_output *base, + const char *gbm_format) +{ + struct rdp_output *output = to_rdp_output(base); + struct rdp_backend *b = to_rdp_backend(base->compositor); + + if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1) + output->gbm_format = b->gbm_format; +} + static int rdp_output_enable(struct weston_output *base) { @@ -530,15 +821,25 @@ rdp_output_enable(struct weston_output *base) NULL, output->base.current_mode->width * 4); if (output->shadow_surface == NULL) { - weston_log("Failed to create surface for frame buffer.\n"); + weston_log("Failed to create SW surface for frame buffer.\n"); return -1; } - if (pixman_renderer_output_create(&output->base) < 0) { + if (b->use_pixman) { + if (pixman_renderer_output_create(&output->base) < 0) { + pixman_image_unref(output->shadow_surface); + return -1; + } + } else if (rdp_output_init_egl(output, b) < 0) { + weston_log("Failed to init output gl state\n"); pixman_image_unref(output->shadow_surface); return -1; } + if (!b->use_pixman) { + if (rdp_get_image_size(output) < 0) return -1; + } + loop = wl_display_get_event_loop(b->compositor->wl_display); output->finish_frame_timer = wl_event_loop_add_timer(loop, finish_frame_handler, output); @@ -557,7 +858,11 @@ rdp_output_disable(struct weston_output *base) return 0; pixman_image_unref(output->shadow_surface); - pixman_renderer_output_destroy(&output->base); + + if (b->use_pixman) + pixman_renderer_output_destroy(&output->base); + else + rdp_output_fini_egl(output); wl_event_source_remove(output->finish_frame_timer); b->output = NULL; @@ -603,6 +908,13 @@ rdp_destroy(struct weston_compositor *ec) int i; weston_compositor_shutdown(ec); + + if (!b->use_pixman) { + gbm_device_destroy(b->gbm); + close(b->drm_fd); + udev_unref(b->udev); + } + for (i = 0; i < MAX_FREERDP_FDS; i++) if (b->listener_events[i]) wl_event_source_remove(b->listener_events[i]); @@ -1281,6 +1593,7 @@ rdp_incoming_peer(freerdp_listener *instance, freerdp_peer *client) static const struct weston_rdp_output_api api = { rdp_output_set_size, + rdp_output_set_gbm_format }; static struct rdp_backend * @@ -1300,6 +1613,22 @@ rdp_backend_create(struct weston_compositor *compositor, b->base.destroy = rdp_destroy; b->rdp_key = config->rdp_key ? strdup(config->rdp_key) : NULL; b->no_clients_resize = config->no_clients_resize; + b->use_pixman = config->use_pixman; + + if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0) + goto err_compositor; + + b->udev = udev_new(); + if (b->udev == NULL) { + weston_log("failed to initialize udev context\n"); + goto err_compositor; + } + + b->drm_fd = open_drm_device(b->udev); + if (b->drm_fd < 0) { + weston_log("failed to find a suitable drm render node\n"); + goto err_udev; + } compositor->backend = &b->base; @@ -1314,13 +1643,22 @@ rdp_backend_create(struct weston_compositor *compositor, } if (weston_compositor_set_presentation_clock_software(compositor) < 0) - goto err_compositor; + goto err_udev; - if (pixman_renderer_init(compositor) < 0) - goto err_compositor; + if (b->use_pixman) { + if (init_pixman(b) < 0) { + weston_log("failed to initialize pixman renderer\n"); + goto err_udev; + } + } else { + if (init_egl(b) < 0) { + weston_log("failed to initialize egl\n"); + goto err_udev; + } + } if (rdp_backend_create_output(compositor) < 0) - goto err_compositor; + goto err_udev; compositor->capabilities |= WESTON_CAP_ARBITRARY_MODES; @@ -1363,6 +1701,8 @@ err_listener: freerdp_listener_free(b->listener); err_output: weston_output_release(&b->output->base); +err_udev: + udev_unref(b->udev); err_compositor: weston_compositor_shutdown(compositor); err_free_strings: @@ -1383,6 +1723,7 @@ config_init_to_defaults(struct weston_rdp_backend_config *config) config->server_key = NULL; config->env_socket = 0; config->no_clients_resize = 0; + config->use_pixman = 0; } WL_EXPORT int diff --git a/libweston/compositor-rdp.h b/libweston/compositor-rdp.h index bd0a6a9..f3d77c8 100644 --- a/libweston/compositor-rdp.h +++ b/libweston/compositor-rdp.h @@ -42,6 +42,15 @@ struct weston_rdp_output_api { */ int (*output_set_size)(struct weston_output *output, int width, int height); + + /** The pixel format to be used by the output. Valid values are: + * - NULL - The format set at backend creation time will be used; + * - "xrgb8888"; + * - "rgb565" + * - "xrgb2101010" + */ + void (*set_gbm_format)(struct weston_output *output, + const char *gbm_format); }; static inline const struct weston_rdp_output_api * @@ -65,6 +74,21 @@ struct weston_rdp_backend_config { char *server_key; int env_socket; int no_clients_resize; + + /** Whether to use the pixman renderer instead of the OpenGL ES renderer. */ + bool use_pixman; + + /** The pixel format of the framebuffer to be used. + * + * Valid values are: + * - NULL - The default format ("xrgb8888") will be used; + * - "xrgb8888"; + * - "rgb565" + * - "xrgb2101010" + * The backend will take ownership of the format pointer and will free + * it on backend destruction. + */ + char *gbm_format; }; #ifdef __cplusplus -- Raimun. -----Mensaje original----- De: wayland-devel [mailto:wayland-devel-boun...@lists.freedesktop.org] En nombre de Pekka Paalanen Enviado el: martes, 03 de abril de 2018 15:39 Para: Raimundo Sagarzazu CC: wayland-devel@lists.freedesktop.org Asunto: Re: [PATCH 3/3] rdp-backend.so: OpenGL hardware acceleration On Fri, 23 Feb 2018 16:08:00 +0100 Raimundo Sagarzazu <rsagarz...@ulmapackaging.com> wrote: > Hi, > > Two patches that improve performance in my case. > > First, supporting ARGB8888 gbm-format for the output allows a much better > performance of the intelReadPixels function of the i965 driver of Mesa, which > is my case: > > diff -rup a/libweston/compositor-rdp.c b/libweston/compositor-rdp.c > --- a/libweston/compositor-rdp.c 2018-02-22 11:35:14.000000000 +0100 > +++ b/libweston/compositor-rdp.c 2018-02-22 11:37:20.312159332 +0100 > @@ -592,6 +592,8 @@ parse_gbm_format(const char *s, uint32_t > *gbm_format = default_value; > else if (strcmp(s, "xrgb8888") == 0) > *gbm_format = GBM_FORMAT_XRGB8888; > + else if (strcmp(s, "argb8888") == 0) > + *gbm_format = GBM_FORMAT_ARGB8888; > else if (strcmp(s, "rgb565") == 0) > *gbm_format = GBM_FORMAT_RGB565; > else if (strcmp(s, "xrgb2101010") == 0) > > Second, reading just the damaged pixels and y-flipping back the image: Hi, thanks for the patches, the ideas look good to me, but the patches themselves are not formatted such that they could be applied. Please see https://cgit.freedesktop.org/wayland/wayland/tree/doc/Contributing for some guidance. I would expect a re-send of these patches. The OpenGL support in RDP-backend has not been merged yet, so it would be good to point to the depended-on patches in your cover letter or even offer a branch from which people could test. Thanks, pq _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel