Le 06/07/2017 à 12:06, Olivier Blin a écrit : > From: DRC <informat...@virtualgl.org> > > --- > compositor/main.c | 23 +++- > configure.ac | 4 +- > libweston/compositor-rdp.c | 314 > +++++++++++++++++++++++++++++++++++++++++++-- > libweston/compositor-rdp.h | 24 ++++ > 4 files changed, 352 insertions(+), 13 deletions(-) > > diff --git a/compositor/main.c b/compositor/main.c > index f8a60e97..125cc0f8 100644 > --- a/compositor/main.c > +++ b/compositor/main.c > @@ -601,6 +601,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 > > @@ -1331,11 +1332,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); > > @@ -1344,6 +1348,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; > > @@ -1353,6 +1359,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); > @@ -1375,6 +1387,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 > @@ -1382,6 +1395,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); > @@ -1399,11 +1413,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); > > @@ -1417,6 +1437,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 53faee34..a7b2d517 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -250,9 +250,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 7b1ab06d..b8c390d0 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 > @@ -79,6 +85,7 @@ > #include "shared/helpers.h" > #include "compositor.h" > #include "compositor-rdp.h" > +#include "gl-renderer.h" > #include "pixman-renderer.h" > > #define MAX_FREERDP_FDS 32 > @@ -110,6 +117,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 { > @@ -128,6 +142,8 @@ 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; > > struct wl_list peers; > @@ -160,6 +176,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) > { > @@ -364,12 +382,24 @@ 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) { > + /* TODO: Performance: Only read pixels that was > actually repained by renderer->repaint_output. */ > + ec->renderer->read_pixels(output_base, > + > pixman_image_get_format(output->shadow_surface), > + > pixman_image_get_data(output->shadow_surface), > + 0, 0, > + > pixman_image_get_width(output->shadow_surface), > + > pixman_image_get_height(output->shadow_surface)); > + } > + > wl_list_for_each(outputPeer, &output->peers, link) { > if ((outputPeer->flags & RDP_PEER_ACTIVATED) && > (outputPeer->flags & > RDP_PEER_OUTPUT_ENABLED)) > @@ -426,9 +456,203 @@ 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, "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_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; > @@ -448,8 +672,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); > @@ -517,6 +754,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,11 +778,17 @@ 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; > } > @@ -557,7 +811,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; > @@ -608,6 +866,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 +1546,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 * > @@ -1301,6 +1567,22 @@ rdp_backend_create(struct weston_compositor > *compositor, > b->base.restore = rdp_restore; > 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; > + } > > /* activate TLS only if certificate/key are available */ > if (config->server_cert && config->server_key) { > @@ -1313,13 +1595,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; > > @@ -1364,6 +1655,8 @@ err_listener: > freerdp_listener_free(b->listener); > err_output: > weston_output_destroy(&b->output->base); > +err_udev: > + udev_unref(b->udev); > err_compositor: > weston_compositor_shutdown(compositor); > err_free_strings: > @@ -1384,6 +1677,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 bd0a6a90..f3d77c88 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 >
Reviewed-by: David Fort <cont...@hardening-consulting.com> -- David FORT website: http://www.hardening-consulting.com/ _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel