[PATCH v2 2/2] x11 backend: add option to use pixman renderer

John Kåre Alsaker john.kare.alsaker at gmail.com
Mon Jan 7 11:09:37 PST 2013


The use-shm variable (which I assume stand for use-x11-shm) and
configuration option should probably be renamed to use-pixman so it
could be used with multiple backends and not be easily confused with
wl_shm.

On Mon, Jan 7, 2013 at 7:49 PM, Kristian Høgsberg <hoegsberg at gmail.com> wrote:
> On Mon, Jan 07, 2013 at 08:39:50PM +0300, Vasily Khoruzhick wrote:
>> When --use-shm is passed to weston and x11 backend is active,
>> it will use SHM surfaces with pixman renderer instead of EGL
>>
>> Signed-off-by: Vasily Khoruzhick <anarsoul at gmail.com>
>> ---
>> v2: - handle missing MIT-SHM extension gracefully (tested with Xnest)
>>     - follow libc convention of error handling
>>     - get rid of xcb-aux dependency
>
> Looks good, committed.  Is there a reason you don't just use
> visual_type->depth instead of get_depth_of_visual()?  Maybe I'm
> missing something.  Also, to test the pixman renderer with desktop
> shell, I have to comment out
>
> #define HAVE_CAIRO_EGL 1
>
> in config.h, since we don't have a configure option to disable that.
> If you feel like making a patch to add --disable-egl or such, that
> would be great.  And of course, it would be nice to make the
> pixman-renderer work with the kms backend.
>
> Anyway, thanks a lot, I really appreciate this work.  It's a great
> validation of the weston_renderer infrastructure and of course it's
> very cool that we can now run weston without hw acceleration without
> having to rely on sw mesa.
>
> Kristian
>
>>  src/compositor-x11.c | 355 +++++++++++++++++++++++++++++++++++++++++++++++++--
>>  1 file changed, 342 insertions(+), 13 deletions(-)
>>
>> diff --git a/src/compositor-x11.c b/src/compositor-x11.c
>> index 04a1803..a994a97 100644
>> --- a/src/compositor-x11.c
>> +++ b/src/compositor-x11.c
>> @@ -1,6 +1,7 @@
>>  /*
>>   * Copyright © 2008-2011 Kristian Høgsberg
>>   * Copyright © 2010-2011 Intel Corporation
>> + * Copyright © 2013 Vasily Khoruzhick <anarsoul at gmail.com>
>>   *
>>   * Permission to use, copy, modify, distribute, and sell this software and
>>   * its documentation for any purpose is hereby granted without fee, provided
>> @@ -33,9 +34,11 @@
>>  #include <unistd.h>
>>  #include <errno.h>
>>  #include <sys/time.h>
>> +#include <sys/shm.h>
>>  #include <linux/input.h>
>>
>>  #include <xcb/xcb.h>
>> +#include <xcb/shm.h>
>>  #ifdef HAVE_XCB_XKB
>>  #include <xcb/xkb.h>
>>  #endif
>> @@ -47,6 +50,7 @@
>>
>>  #include "compositor.h"
>>  #include "gl-renderer.h"
>> +#include "pixman-renderer.h"
>>  #include "../shared/config-parser.h"
>>  #include "../shared/cairo-util.h"
>>
>> @@ -79,6 +83,7 @@ struct x11_compositor {
>>       struct xkb_keymap       *xkb_keymap;
>>       unsigned int             has_xkb;
>>       uint8_t                  xkb_event_base;
>> +     int                      use_shm;
>>
>>       /* We could map multi-pointer X to multiple wayland seats, but
>>        * for now we only support core X input. */
>> @@ -107,6 +112,15 @@ struct x11_output {
>>       xcb_window_t            window;
>>       struct weston_mode      mode;
>>       struct wl_event_source *finish_frame_timer;
>> +
>> +     xcb_gc_t                gc;
>> +     xcb_shm_seg_t           segment;
>> +     pixman_image_t         *hw_surface;
>> +     pixman_image_t         *shadow_surface;
>> +     int                     shm_id;
>> +     void                   *buf;
>> +     void                   *shadow_buf;
>> +     uint8_t                 depth;
>>  };
>>
>>  static struct xkb_keymap *
>> @@ -307,16 +321,95 @@ x11_input_destroy(struct x11_compositor *compositor)
>>  }
>>
>>  static void
>> -x11_output_repaint(struct weston_output *output_base,
>> -                pixman_region32_t *damage)
>> +x11_output_repaint_gl(struct weston_output *output_base,
>> +                   pixman_region32_t *damage)
>> +{
>> +     struct x11_output *output = (struct x11_output *)output_base;
>> +     struct weston_compositor *ec = output->base.compositor;
>> +
>> +     ec->renderer->repaint_output(output_base, damage);
>> +
>> +     pixman_region32_subtract(&ec->primary_plane.damage,
>> +                              &ec->primary_plane.damage, damage);
>> +
>> +     wl_event_source_timer_update(output->finish_frame_timer, 10);
>> +}
>> +
>> +static void
>> +x11_output_repaint_shm(struct weston_output *output_base,
>> +                    pixman_region32_t *damage)
>>  {
>>       struct x11_output *output = (struct x11_output *)output_base;
>>       struct weston_compositor *ec = output->base.compositor;
>> +     struct x11_compositor *c = (struct x11_compositor *)ec;
>> +     pixman_box32_t *rects;
>> +     int nrects, i, src_x, src_y, x1, y1, x2, y2, width, height;
>> +     xcb_void_cookie_t cookie;
>> +     xcb_generic_error_t *err;
>>
>> +     pixman_renderer_output_set_buffer(output_base, output->shadow_surface);
>>       ec->renderer->repaint_output(output_base, damage);
>>
>> +     width = pixman_image_get_width(output->shadow_surface);
>> +     height = pixman_image_get_height(output->shadow_surface);
>> +     rects = pixman_region32_rectangles(damage, &nrects);
>> +     for (i = 0; i < nrects; i++) {
>> +             switch (output_base->transform) {
>> +             default:
>> +             case WL_OUTPUT_TRANSFORM_NORMAL:
>> +                     x1 = rects[i].x1;
>> +                     x2 = rects[i].x2;
>> +                     y1 = rects[i].y1;
>> +                     y2 = rects[i].y2;
>> +                     break;
>> +             case WL_OUTPUT_TRANSFORM_180:
>> +                     x1 = width - rects[i].x2;
>> +                     x2 = width - rects[i].x1;
>> +                     y1 = height - rects[i].y2;
>> +                     y2 = height - rects[i].y1;
>> +                     break;
>> +             case WL_OUTPUT_TRANSFORM_90:
>> +                     x1 = height - rects[i].y2;
>> +                     x2 = height - rects[i].y1;
>> +                     y1 = rects[i].x1;
>> +                     y2 = rects[i].x2;
>> +                     break;
>> +             case WL_OUTPUT_TRANSFORM_270:
>> +                     x1 = rects[i].y1;
>> +                     x2 = rects[i].y2;
>> +                     y1 = width - rects[i].x2;
>> +                     y2 = width - rects[i].x1;
>> +                     break;
>> +             }
>> +             src_x = x1;
>> +             src_y = y1;
>> +
>> +             pixman_image_composite32(PIXMAN_OP_SRC,
>> +                     output->shadow_surface, /* src */
>> +                     NULL /* mask */,
>> +                     output->hw_surface, /* dest */
>> +                     src_x, src_y, /* src_x, src_y */
>> +                     0, 0, /* mask_x, mask_y */
>> +                     x1, y1, /* dest_x, dest_y */
>> +                     x2 - x1, /* width */
>> +                     y2 - y1 /* height */);
>> +     }
>> +
>>       pixman_region32_subtract(&ec->primary_plane.damage,
>>                                &ec->primary_plane.damage, damage);
>> +     cookie = xcb_shm_put_image_checked(c->conn, output->window, output->gc,
>> +                                     pixman_image_get_width(output->hw_surface),
>> +                                     pixman_image_get_height(output->hw_surface),
>> +                                     0, 0,
>> +                                     pixman_image_get_width(output->hw_surface),
>> +                                     pixman_image_get_height(output->hw_surface),
>> +                                     0, 0, output->depth, XCB_IMAGE_FORMAT_Z_PIXMAP,
>> +                                     0, output->segment, 0);
>> +     err = xcb_request_check(c->conn, cookie);
>> +     if (err != NULL) {
>> +             weston_log("Failed to put shm image, err: %d\n", err->error_code);
>> +             free(err);
>> +     }
>>
>>       wl_event_source_timer_update(output->finish_frame_timer, 10);
>>  }
>> @@ -336,6 +429,28 @@ finish_frame_handler(void *data)
>>  }
>>
>>  static void
>> +x11_output_deinit_shm(struct x11_compositor *c, struct x11_output *output)
>> +{
>> +     xcb_void_cookie_t cookie;
>> +     xcb_generic_error_t *err;
>> +     xcb_free_gc(c->conn, output->gc);
>> +
>> +     pixman_image_unref(output->hw_surface);
>> +     output->hw_surface = NULL;
>> +     cookie = xcb_shm_detach_checked(c->conn, output->segment);
>> +     err = xcb_request_check(c->conn, cookie);
>> +     if (err) {
>> +             weston_log("xcb_shm_detach failed, error %d\n", err->error_code);
>> +             free(err);
>> +     }
>> +     shmdt(output->buf);
>> +
>> +     pixman_image_unref(output->shadow_surface);
>> +     output->shadow_surface = NULL;
>> +     free(output->shadow_buf);
>> +}
>> +
>> +static void
>>  x11_output_destroy(struct weston_output *output_base)
>>  {
>>       struct x11_output *output = (struct x11_output *)output_base;
>> @@ -345,7 +460,11 @@ x11_output_destroy(struct weston_output *output_base)
>>       wl_list_remove(&output->base.link);
>>       wl_event_source_remove(output->finish_frame_timer);
>>
>> -     gl_renderer_output_destroy(output_base);
>> +     if (compositor->use_shm) {
>> +             pixman_renderer_output_destroy(output_base);
>> +             x11_output_deinit_shm(compositor, output);
>> +     } else
>> +             gl_renderer_output_destroy(output_base);
>>
>>       xcb_destroy_window(compositor->conn, output->window);
>>
>> @@ -456,6 +575,186 @@ x11_output_wait_for_map(struct x11_compositor *c, struct x11_output *output)
>>       }
>>  }
>>
>> +static xcb_visualtype_t *
>> +find_visual_by_id(xcb_screen_t *screen,
>> +                xcb_visualid_t id)
>> +{
>> +     xcb_depth_iterator_t i;
>> +     xcb_visualtype_iterator_t j;
>> +     for (i = xcb_screen_allowed_depths_iterator(screen);
>> +          i.rem;
>> +          xcb_depth_next(&i)) {
>> +             for (j = xcb_depth_visuals_iterator(i.data);
>> +                  j.rem;
>> +                  xcb_visualtype_next(&j)) {
>> +                     if (j.data->visual_id == id)
>> +                             return j.data;
>> +             }
>> +     }
>> +     return 0;
>> +}
>> +
>> +static uint8_t
>> +get_depth_of_visual(xcb_screen_t *screen,
>> +                xcb_visualid_t id)
>> +{
>> +     xcb_depth_iterator_t i;
>> +     xcb_visualtype_iterator_t j;
>> +     for (i = xcb_screen_allowed_depths_iterator(screen);
>> +          i.rem;
>> +          xcb_depth_next(&i)) {
>> +             for (j = xcb_depth_visuals_iterator(i.data);
>> +                  j.rem;
>> +                  xcb_visualtype_next(&j)) {
>> +                     if (j.data->visual_id == id)
>> +                             return i.data->depth;
>> +             }
>> +     }
>> +     return 0;
>> +}
>> +
>> +static int
>> +x11_output_init_shm(struct x11_compositor *c, struct x11_output *output,
>> +     int width, int height)
>> +{
>> +     xcb_screen_iterator_t iter;
>> +     xcb_visualtype_t *visual_type;
>> +     xcb_format_iterator_t fmt;
>> +     xcb_void_cookie_t cookie;
>> +     xcb_generic_error_t *err;
>> +     int shadow_width, shadow_height;
>> +     pixman_transform_t transform;
>> +     const xcb_query_extension_reply_t *ext;
>> +     int bitsperpixel = 0;
>> +     pixman_format_code_t pixman_format;
>> +
>> +     /* Check if SHM is available */
>> +     ext = xcb_get_extension_data(c->conn, &xcb_shm_id);
>> +     if (ext == NULL || !ext->present) {
>> +             /* SHM is missing */
>> +             weston_log("SHM extension is not available\n");
>> +             errno = ENOENT;
>> +             return -1;
>> +     }
>> +
>> +     iter = xcb_setup_roots_iterator(xcb_get_setup(c->conn));
>> +     visual_type = find_visual_by_id(iter.data, iter.data->root_visual);
>> +     if (!visual_type) {
>> +             weston_log("Failed to lookup visual for root window\n");
>> +             errno = ENOENT;
>> +             return -1;
>> +     }
>> +     weston_log("Found visual, bits per value: %d, red_mask: %.8x, green_mask: %.8x, blue_mask: %.8x\n",
>> +             visual_type->bits_per_rgb_value,
>> +             visual_type->red_mask,
>> +             visual_type->green_mask,
>> +             visual_type->blue_mask);
>> +     output->depth = get_depth_of_visual(iter.data, iter.data->root_visual);
>> +     weston_log("Visual depth is %d\n", output->depth);
>> +
>> +     for (fmt = xcb_setup_pixmap_formats_iterator(xcb_get_setup(c->conn));
>> +          fmt.rem;
>> +          xcb_format_next(&fmt)) {
>> +             if (fmt.data->depth == output->depth) {
>> +                     bitsperpixel = fmt.data->bits_per_pixel;
>> +                     break;
>> +             }
>> +     }
>> +     weston_log("Found format for depth %d, bpp: %d\n",
>> +             output->depth, bitsperpixel);
>> +
>> +     if  (bitsperpixel == 32 &&
>> +          visual_type->red_mask == 0xff0000 &&
>> +          visual_type->green_mask == 0x00ff00 &&
>> +          visual_type->blue_mask == 0x0000ff) {
>> +             weston_log("Will use x8r8g8b8 format for SHM surfaces\n");
>> +             pixman_format = PIXMAN_x8r8g8b8;
>> +     } else {
>> +             weston_log("Can't find appropriate format for SHM pixmap\n");
>> +             errno = ENOTSUP;
>> +             return -1;
>> +     }
>> +
>> +
>> +     /* Create SHM segment and attach it */
>> +     output->shm_id = shmget(IPC_PRIVATE, width * height * (bitsperpixel / 8), IPC_CREAT | S_IRWXU);
>> +     if (output->shm_id == -1) {
>> +             weston_log("x11shm: failed to allocate SHM segment\n");
>> +             return -1;
>> +     }
>> +     output->buf = shmat(output->shm_id, NULL, 0 /* read/write */);
>> +     if (-1 == (long)output->buf) {
>> +             weston_log("x11shm: failed to attach SHM segment\n");
>> +             return -1;
>> +     }
>> +     output->segment = xcb_generate_id(c->conn);
>> +     cookie = xcb_shm_attach_checked(c->conn, output->segment, output->shm_id, 1);
>> +     err = xcb_request_check(c->conn, cookie);
>> +     if (err) {
>> +             weston_log("x11shm: xcb_shm_attach error %d\n", err->error_code);
>> +             free(err);
>> +             return -1;
>> +     }
>> +
>> +     shmctl(output->shm_id, IPC_RMID, NULL);
>> +
>> +     /* Now create pixman image */
>> +     output->hw_surface = pixman_image_create_bits(pixman_format, width, height, output->buf,
>> +             width * (bitsperpixel / 8));
>> +     pixman_transform_init_identity(&transform);
>> +     switch (output->base.transform) {
>> +     default:
>> +     case WL_OUTPUT_TRANSFORM_NORMAL:
>> +             shadow_width = width;
>> +             shadow_height = height;
>> +             pixman_transform_rotate(&transform,
>> +                     NULL, 0, 0);
>> +             pixman_transform_translate(&transform, NULL,
>> +                     0, 0);
>> +             break;
>> +     case WL_OUTPUT_TRANSFORM_180:
>> +             shadow_width = width;
>> +             shadow_height = height;
>> +             pixman_transform_rotate(&transform,
>> +                     NULL, -pixman_fixed_1, 0);
>> +             pixman_transform_translate(NULL, &transform,
>> +                     pixman_int_to_fixed(shadow_width),
>> +                     pixman_int_to_fixed(shadow_height));
>> +             break;
>> +     case WL_OUTPUT_TRANSFORM_270:
>> +             shadow_width = height;
>> +             shadow_height = width;
>> +             pixman_transform_rotate(&transform,
>> +                     NULL, 0, pixman_fixed_1);
>> +             pixman_transform_translate(&transform,
>> +                     NULL,
>> +                     pixman_int_to_fixed(shadow_width),
>> +                     0);
>> +             break;
>> +     case WL_OUTPUT_TRANSFORM_90:
>> +             shadow_width = height;
>> +             shadow_height = width;
>> +             pixman_transform_rotate(&transform,
>> +                     NULL, 0, -pixman_fixed_1);
>> +             pixman_transform_translate(&transform,
>> +                     NULL,
>> +                     0,
>> +                     pixman_int_to_fixed(shadow_height));
>> +             break;
>> +     }
>> +     output->shadow_buf = malloc(width * height *  (bitsperpixel / 8));
>> +     output->shadow_surface = pixman_image_create_bits(pixman_format, shadow_width, shadow_height,
>> +             output->shadow_buf, shadow_width * (bitsperpixel / 8));
>> +     /* No need in transform for normal output */
>> +     if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
>> +             pixman_image_set_transform(output->shadow_surface, &transform);
>> +
>> +     output->gc = xcb_generate_id(c->conn);
>> +     xcb_create_gc(c->conn, output->gc, output->window, 0, NULL);
>> +
>> +     return 0;
>> +}
>> +
>>  static struct x11_output *
>>  x11_compositor_create_output(struct x11_compositor *c, int x, int y,
>>                            int width, int height, int fullscreen,
>> @@ -562,7 +861,10 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
>>       x11_output_wait_for_map(c, output);
>>
>>       output->base.origin = output->base.current;
>> -     output->base.repaint = x11_output_repaint;
>> +     if (c->use_shm)
>> +             output->base.repaint = x11_output_repaint_shm;
>> +     else
>> +             output->base.repaint = x11_output_repaint_gl;
>>       output->base.destroy = x11_output_destroy;
>>       output->base.assign_planes = NULL;
>>       output->base.set_backlight = NULL;
>> @@ -574,8 +876,17 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
>>       weston_output_init(&output->base, &c->base,
>>                          x, y, width, height, transform);
>>
>> -     if (gl_renderer_output_create(&output->base, output->window) < 0)
>> -             return NULL;
>> +     if (c->use_shm) {
>> +             if (x11_output_init_shm(c, output, width, height) < 0)
>> +                     return NULL;
>> +             if (pixman_renderer_output_create(&output->base) < 0) {
>> +                     x11_output_deinit_shm(c, output);
>> +                     return NULL;
>> +             }
>> +     } else {
>> +             if (gl_renderer_output_create(&output->base, output->window) < 0)
>> +                     return NULL;
>> +     }
>>
>>       loop = wl_display_get_event_loop(c->base.wl_display);
>>       output->finish_frame_timer =
>> @@ -1108,7 +1419,10 @@ x11_destroy(struct weston_compositor *ec)
>>
>>       weston_compositor_shutdown(ec); /* destroys outputs, too */
>>
>> -     gl_renderer_destroy(ec);
>> +     if (compositor->use_shm)
>> +             pixman_renderer_destroy(ec);
>> +     else
>> +             gl_renderer_destroy(ec);
>>
>>       XCloseDisplay(compositor->dpy);
>>       free(ec);
>> @@ -1118,6 +1432,7 @@ static struct weston_compositor *
>>  x11_compositor_create(struct wl_display *display,
>>                     int fullscreen,
>>                     int no_input,
>> +                   int use_shm,
>>                     int argc, char *argv[], const char *config_file)
>>  {
>>       struct x11_compositor *c;
>> @@ -1156,15 +1471,23 @@ x11_compositor_create(struct wl_display *display,
>>       x11_compositor_get_resources(c);
>>
>>       c->base.wl_display = display;
>> -     if (gl_renderer_create(&c->base, c->dpy, gl_renderer_opaque_attribs,
>> -                     NULL) < 0)
>> -             goto err_xdisplay;
>> +     c->use_shm = use_shm;
>> +     if (c->use_shm) {
>> +             if (pixman_renderer_init(&c->base) < 0)
>> +                     goto err_xdisplay;
>> +     }
>> +     else {
>> +             if (gl_renderer_create(&c->base, c->dpy, gl_renderer_opaque_attribs,
>> +                             NULL) < 0)
>> +                     goto err_xdisplay;
>> +     }
>> +     weston_log("Using %s renderer\n", use_shm ? "pixman" : "gl");
>>
>>       c->base.destroy = x11_destroy;
>>       c->base.restore = x11_restore;
>>
>>       if (x11_input_create(c, no_input) < 0)
>> -             goto err_gl;
>> +             goto err_renderer;
>>
>>       width = option_width ? option_width : 1024;
>>       height = option_height ? option_height : 640;
>> @@ -1208,8 +1531,11 @@ x11_compositor_create(struct wl_display *display,
>>
>>  err_x11_input:
>>       x11_input_destroy(c);
>> -err_gl:
>> -     gl_renderer_destroy(&c->base);
>> +err_renderer:
>> +     if (c->use_shm)
>> +             pixman_renderer_destroy(&c->base);
>> +     else
>> +             gl_renderer_destroy(&c->base);
>>  err_xdisplay:
>>       XCloseDisplay(c->dpy);
>>  err_free:
>> @@ -1298,6 +1624,7 @@ backend_init(struct wl_display *display, int argc, char *argv[],
>>  {
>>       int fullscreen = 0;
>>       int no_input = 0;
>> +     int use_shm = 0;
>>
>>       const struct weston_option x11_options[] = {
>>               { WESTON_OPTION_INTEGER, "width", 0, &option_width },
>> @@ -1305,6 +1632,7 @@ backend_init(struct wl_display *display, int argc, char *argv[],
>>               { WESTON_OPTION_BOOLEAN, "fullscreen", 'f', &fullscreen },
>>               { WESTON_OPTION_INTEGER, "output-count", 0, &option_count },
>>               { WESTON_OPTION_BOOLEAN, "no-input", 0, &no_input },
>> +             { WESTON_OPTION_BOOLEAN, "use-shm", 0, &use_shm },
>>       };
>>
>>       parse_options(x11_options, ARRAY_LENGTH(x11_options), argc, argv);
>> @@ -1328,5 +1656,6 @@ backend_init(struct wl_display *display, int argc, char *argv[],
>>       return x11_compositor_create(display,
>>                                    fullscreen,
>>                                    no_input,
>> +                                  use_shm,
>>                                    argc, argv, config_file);
>>  }
>> --
>> 1.8.1
>>
>> _______________________________________________
>> wayland-devel mailing list
>> wayland-devel at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the wayland-devel mailing list